New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[CS2] An explanation of why we don’t currently support certain features #4469
Changes from 3 commits
97aef9b
608799f
3aa177c
a6bf72a
5888ac5
06f6efa
b8df321
27caf62
d0c6e53
0c06fb2
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
## Contributing | ||
Contributions are welcome, feel free to fork a copy and submit a pull request. | ||
|
||
If there is a core part of ECMAScript you think we are missing, head on over to [CoffeeScript issues on GitHub](http://github.com/jashkenas/coffeescript/issues), and dig around in the open and closed issues. | ||
|
||
For more resources on adding to CoffeeScript, please see [the Wiki](https://github.com/jashkenas/coffeescript/wiki/%5BHowto%5D-Hacking-on-the-CoffeeScript-Compiler) or [How The Parser Works](https://github.com/jashkenas/coffeescript/wiki/%5BHowTo%5D-How-parsing-works) if you are interested in learning how the parser works. | ||
|
||
There are several things you can do to increase your odds of having the pull request accepted: | ||
|
||
* Create tests! Any pull request should probably include basic tests to verify you didn't break anything, or future changes won't break your code. | ||
* Follow the CoffeeScript style guide | ||
* Ensure any ECMAScript addition is mature (at Stage 4), with no further potential syntax changes. | ||
* Make sure that you are keeping to the core ideas of CoffeeScript | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is vague, we could just leave it out. |
||
* Adding only the features that help the community rather than a specific use case. | ||
|
||
Of course, it's entirely possible that you have a great addition, but it doesn't fit directly with the CoffeeScript code base. | ||
|
||
This might be the time to... | ||
|
||
## Roll Your Own | ||
|
||
You are of course, welcome to fork the language and add in the features you want. There are quite a few really interesting projects that have done so, and more are welcome. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section should include a link to the wiki page where Jeremy has compiled a list of CoffeeScript’s derivatives. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
## get and set | ||
Get and set are intentionally not implemented as keywords in CoffeeScript. | ||
|
||
This is by design. While using get/set is still possible, CoffeeScript considers them anti-patterns. | ||
|
||
In ECMAScript these convenience function decorators were introduced for very specific uses with the browser DOM. | ||
|
||
If you are still convinced you need to use `get`/`set`, here are some workarounds: | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think the documentation should avoid sounding judgmental. This section should probably be written more like:
|
||
|
||
* Use a [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy). Also see an [example of using Proxy](https://nemisj.com/why-getterssetters-is-a-bad-idea-in-javascript/). | ||
* Add them direcly [the long way round](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty). |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
## let and const | ||
|
||
`let` and `const` are intentionally left out of CoffeeScript at this time. | ||
|
||
These keywords don't fit in with the core tennents of CoffeeScript, and are easily mitigated by careful naming and thoughtful design. The benefit is a lot less typing on your part. | ||
|
||
Neither keyword adds sufficient value, especially when we compare them against a few of the core tennents: | ||
|
||
* Don't have to think about variable declaration | ||
* Be terse | ||
* Reduce complexity | ||
* Keep your code clean | ||
* Reduce code quality issues | ||
* Increase readability | ||
* Bring out the best from ECMAScript | ||
|
||
Ah! You might think, that is all very well and good, but I make a lot of mistakes in my code, and these keywords protect me from myself and others! | ||
|
||
Well, indeed these keywords may help you. However CoffeeScript has already dealt with some of these issues. | ||
|
||
Let's explore a little. | ||
|
||
### The `let` Keyword | ||
|
||
Quite a lot of time was spent trying to find reasons to generate `let` in our latest branch, and what rules we would need to check. | ||
|
||
After quite a bit of testing it turned out that `let` wasn't really much of an advantage over var. CoffeeScript was originally written to help deal with scope leakage and already implements _all variables as var_ and in the correct scope. CoffeeScript doesn't have the issue of accidental global variables. | ||
|
||
```coffeescript | ||
|
||
a = 5 | ||
b = () -> | ||
c = 6 | ||
|
||
``` | ||
|
||
And our resulting ECMAScript: | ||
|
||
|
||
```javascript | ||
|
||
// Generated by CoffeeScript 2.0.0-alpha1 | ||
(function() { // We generate the entire file within a closure by default, to avoid variabe leakage. | ||
var a, b; // a, b are visible in all remaining scopes as a result of closures. | ||
// however they are NOT visible globally, only within this file / module. | ||
a = 5; | ||
|
||
b = function() { | ||
var c; // c is not seen outside of this scope. | ||
return c = 6; | ||
}; | ||
|
||
}).call(this); | ||
|
||
``` | ||
|
||
Aha! Right there in that function, you could accidentally override `a`! | ||
|
||
Well this is true. But consider [this conversation](https://github.com/jashkenas/coffeescript/issues/238#issuecomment-153502) in the issues: | ||
|
||
> It's certainly possible to accidentally blow away an outer variable within an inner scope, but (in Ruby and Python), this turns out not to be a very common problem. If you don't nest functions too deeply, don't introduce a lot of globals, and give things proper names, it never arises. | ||
|
||
And here is another useful comment by jashkenas | ||
|
||
> And if they do clash, shadowing the variable is the wrong answer. It completely prevents you from making use of the original value for the remainder of the current scope. Shadowing doesn't fit well in languages with closures-by-default ... if you've closed over that variable, then you should always be able to refer to it. | ||
|
||
If you take the time to name things well, you actually have to go out of your way to clobber another variable. The trade off for making you take more time naming your variables is one less keyword to have to type over and over. | ||
|
||
Hrmmm. Good point. But what about `const`?!? I REALLY want to make everything constant! | ||
|
||
### The `const` Keyword | ||
|
||
`const` is another typical keyword that doesn't really add significant value. Primarily `const` is used to avoid accidental reassignments. In practice this is just like `let` above, make sure you are consistant with scope, and name your variables well. | ||
|
||
`const` also causes a dilemma for CoffeeScript, because suddenly we can get block level shadowing, but it's only const! Well then why not include `let`! Well hopefully you see why we haven't included `let` by now. | ||
So how the heck do I make things constant? | ||
|
||
```coffeescript | ||
|
||
a = 0 | ||
b = 1 | ||
` const c = a + b ` | ||
|
||
c++ # Error - c is a const. | ||
|
||
``` | ||
|
||
|
||
In reality the const keyword refers to the variable itself, _not always the value_ of that object. | ||
|
||
```javascript | ||
|
||
const x = 5; | ||
const y = {}; | ||
x++; // error. Assignment to const | ||
y[x] = x; // {'5': 4} Wait what!?? | ||
y = x; // error. Assignment to const | ||
|
||
``` | ||
|
||
In other words, the statement const x++ doesn't let you change the variable as you would expect. However it WILL let you change the contents of y, because you aren't changing what y is pointing at. It is still the same object! | ||
|
||
You actually have to 'freeze' an object to make it a constant. Use [Object.freeze(obj)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/freeze). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This section is way too long. I would try to reduce it to at most three paragraphs, and link to other sources to add more detail. Also try to write it in a dry tone like the rest of the documentation. Something like: When CoffeeScript was designed,
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
## Unsupported ES5+ Functionality | ||
|
||
There are a few intentional ommisions in the language. | ||
|
||
* `let` / `const` keywords | ||
* `get` / `set` convenience keywords |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,43 @@ | ||
## Why CoffeeScript? | ||
There are a few things you should know about CoffeeScript. | ||
|
||
CoffeeScript is about: | ||
|
||
* Reducing complexity | ||
* Keeping your code clean | ||
* Being terse | ||
* Removing as many 'Bad Parts' as possible | ||
* Reducing code quality issues | ||
* Increasing readability | ||
* Being stable | ||
* Bringing out the best from ECMAScript | ||
|
||
CoffeeScript is NOT about: | ||
|
||
* Having the latest XX/YY feature | ||
* Implementing every aspect of ECMAScript, just because it's there. | ||
* Trying to appease developers from other languages | ||
|
||
There are many style choices within the language, and they have been carefully thought out. Taking time out to understand how CoffeeScript works, and how to work well with it will help you write better, easier to read, safer and more reliable code. | ||
|
||
## Why not just use ECMAScript 7? | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The documentation always refers to ES5 or ES2015 or ES2015+, never “ES6” or “ES7”. |
||
|
||
|
||
ECMAScript has adopted much of the syntax and ideas of CoffeeScript. Unfortunately it still exposes you to many of the 'Bad Parts' of the language. On top of that the ECMASCript syntax is cumulative, allowing a much larger spectrum of potential errors. | ||
|
||
ECMAScript 6/7 are standards, and you should probably know how to work with it. You might assume that working with ECMAScript 6 is more direct or cleaner. But using those newer features still requires a transpiler, for instance Babel. If you consider most front end targetted code still needs a build tool like Grunt, then you will find adding an extra step for CoffeeScript very trivial. | ||
|
||
You will find: | ||
|
||
* CoffeeScript has adopted the vast majority of stable ECMAScript features. | ||
* CoffeeScript protects you by avoiding a wide spectrum of errors. | ||
* You have consistent variable behavior without having to think about context and usage of every variable. | ||
* You reduce cognitive load of the syntax and can get down to solving problems. | ||
* Most parentheses are optional, making functional programming styles much cleaner. | ||
* CoffeeScript forces indenting, which makes code much more readable, and eliminates many nesting errors. | ||
* Most Parentheses go away and no more semicolan errors. | ||
* CoffeeScript has an existential operator `?`, which makes checking for missing elements a breeze. | ||
* CoffeeScript is fully interoperable with ECMAScript code. | ||
* Cleaner syntax for yields, async, and unbound functions `() ->` | ||
|
||
You can learn CoffeeScript in a few hours, and you will be amazed at how much better your code will be. | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This feels like marketing copy. I would maybe rewrite this section to focus on specifically what CoffeeScript offers that ES2015+ doesn’t. There are still many benefits that CoffeeScript has over ES2015+, most importantly (to me) significant whitespace/forced indentation, optional braces and parentheses, and the existential operator. When I introduce people to CoffeeScript and try to convince them of its value, I often use this example, with its JavaScript equivalent side-by-side: if foo?
foo() This illustrates all three of my points:
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,7 @@ | |
<section id="overview"> | ||
<%= htmlFor('introduction') %> | ||
<%= htmlFor('overview') %> | ||
<%= htmlFor('why_coffeescript') %> | ||
</section> | ||
<section id="coffeescript-2"> | ||
<%= htmlFor('coffeescript_2') %> | ||
|
@@ -98,6 +99,15 @@ | |
<%= htmlFor('embedded') %> | ||
</section> | ||
</section> | ||
<section id="unsupported"> | ||
<%= htmlFor('unsupported') %> | ||
<section id="let_const"> | ||
<%= htmlFor('let_const') %> | ||
</section> | ||
<section id="get_set"> | ||
<%= htmlFor('get_set') %> | ||
</section> | ||
</section> | ||
<section id="breaking-changes"> | ||
<%= htmlFor('breaking_changes') %> | ||
</section> | ||
|
@@ -106,7 +116,7 @@ | |
</section> | ||
<section id="source-maps"> | ||
<%= htmlFor('source_maps') %> | ||
</section> | ||
</section> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do you mind please giving me write access to this branch? There are lots of little things like this trailing whitespace, and misspellings, that are easier to just fix than point out in comments. |
||
<section id="cake"> | ||
<%= htmlFor('cake') %> | ||
</section> | ||
|
@@ -130,6 +140,9 @@ | |
<section id="annotated-source"> | ||
<%= htmlFor('annotated_source') %> | ||
</section> | ||
<section id="contributing"> | ||
<%= htmlFor('contributing') %> | ||
</section> | ||
</section> | ||
<section id="changelog"> | ||
<%= htmlFor('changelog') %> | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do we have a style guide? Maybe this should just say that they should follow the style of the rest of the codebase.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can rip this line out. I was thinking that we probably should have a style guide in place.