Merge unsupported `let`/`const` and `get`/`set` sections, shorten

This commit is contained in:
Geoffrey Booth 2017-04-02 22:52:37 -07:00
parent 06f6efa6d5
commit b8df321058
6 changed files with 37 additions and 138 deletions

View File

@ -0,0 +1,9 @@
screen =
width: 1200
ratio: 16/9
Object.defineProperty screen, 'height',
get: ->
this.width / this.ratio
set: (val) ->
this.width = val / this.ratio

View File

@ -1,22 +0,0 @@
## get and set
`get` and `set`, as keywords preceding functions or class methods, are intentionally not implemented in CoffeeScript.
This is to avoid grammatical ambiguity, since in CoffeeScript such a construct looks identical to a function call (e.g. get(function foo() {})) and because there is an alternate syntax that is slightly more verbose but just as effective:
```coffeescript
screen =
width: 1200
ratio: 0.8
Object.defineProperty screen, "height",
get: () ->
screen.width * screen.ratio
set: (val) ->
console.log "Can't set the height."
console.log screen.height # 960
```
Check out [the MDN Reference](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty).
Another alternative is to use a [Proxy object](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy).

View File

@ -1,103 +0,0 @@
## 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).

View File

@ -1,6 +1,27 @@
## Unsupported ES5+ Functionality
## Unsupported ECMAScript Features
There are a few intentional ommisions in the language.
There are a few ECMAScript features that CoffeeScript intentionally doesnt support.
* `let` / `const` keywords
* `get` / `set` convenience keywords
### `let` and `const`: Block-Scoped and Reassignment-Protected Variables
When CoffeeScript was designed, `var` was [intentionally omitted](https://github.com/jashkenas/coffeescript/issues/238#issuecomment-153502). This was to spare developers the mental housekeeping of needing to worry about variable _declaration_ (`var foo`) as opposed to variable _assignment_ (`foo = 1`). The CoffeeScript compiler automatically takes care of declaration for you, by generating `var` statements at the top of every function scope. This makes it impossible to accidentally declare a global variable.
`let` and `const` add a useful ability to JavaScript in that you can use them to declare variables within a _block_ scope, for example within an `if` statement body or a `for` loop body, whereas `var` always declares variables in the scope of an entire function. When CoffeeScript 2 was designed, there was much discussion of whether this functionality was useful enough to outweigh the simplicity offered by never needing to consider variable declaration in CoffeeScript. In the end, it was decided that the simplicity was more valued. In CoffeeScript there remains only one type of variable.
Keep in mind that `const` only protects you from _reassigning_ a variable; it doesnt prevent the variables value from changing, the way constants usually do in other languages:
> ```js
const obj = {foo: 'bar'};
obj.foo = 'baz'; // Allowed!
obj = {}; // Throws error
```
### `get` and `set` Keyword Shorthand Syntax
`get` and `set`, as keywords preceding functions or class methods, are intentionally unimplemented in CoffeeScript.
This is to avoid grammatical ambiguity, since in CoffeeScript such a construct looks identical to a function call (e.g. `get(function foo() {})`); and because there is an [alternate syntax](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty) that is slightly more verbose but just as effective:
```
codeFor('get_set', 'screen.height')
```

View File

@ -101,12 +101,6 @@
</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') %>
@ -116,7 +110,7 @@
</section>
<section id="source-maps">
<%= htmlFor('source_maps') %>
</section>
</section>
<section id="cake">
<%= htmlFor('cake') %>
</section>
@ -142,7 +136,7 @@
</section>
<section id="contributing">
<%= htmlFor('contributing') %>
</section>
</section>
</section>
<section id="changelog">
<%= htmlFor('changelog') %>

View File

@ -85,7 +85,7 @@
<a href="#embedded" class="nav-link" data-action="sidebar-nav">Embedded JavaScript</a>
</li>
<li class="nav-item">
<a href="#unsupported" class="nav-link" data-action="sidebar-nav">Unsupported Features</a>
<a href="#unsupported" class="nav-link" data-action="sidebar-nav">Unsupported ECMAScript Features</a>
</li>
</ul>
</li>