forked from jashkenas/coffeescript
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split apart the “Breaking Changes” and “Unsupported Features” section…
…s into separate sidebar items and files
- Loading branch information
1 parent
9491f71
commit a7b0267
Showing
15 changed files
with
345 additions
and
276 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,144 +1,3 @@ | ||
## Breaking Changes From CoffeeScript 1.x to 2 | ||
|
||
CoffeeScript 2 aims to output as much idiomatic ES2015+ syntax as possible with as few breaking changes from CoffeeScript 1.x as possible. Some breaking changes, unfortunately, were unavoidable. | ||
|
||
<section id="breaking-changes-default-values"> | ||
|
||
### Default values for function parameters and destructured elements | ||
|
||
Per the [ES2015 spec regarding function default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) and [destructuring default values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Default_values), default values are only applied when a value is missing or `undefined`. In CoffeeScript 1.x, the default value would be applied in those cases but also if the value was `null`. | ||
|
||
``` | ||
codeFor('breaking_change_function_parameter_default_values', 'f(null)') | ||
``` | ||
|
||
``` | ||
codeFor('breaking_change_destructuring_default_values', 'a') | ||
``` | ||
|
||
</section> | ||
<section id="breaking-changes-bound-generator-functions"> | ||
|
||
### Bound generator functions | ||
|
||
Bound generator functions, a.k.a. generator arrow functions, [aren’t allowed in ECMAScript](http://stackoverflow.com/questions/27661306/can-i-use-es6s-arrow-function-syntax-with-generators-arrow-notation). You can write `function*` or `=>`, but not both. Therefore, CoffeeScript code like this: | ||
|
||
```coffee | ||
f = => yield this | ||
# Throws a compiler error | ||
``` | ||
|
||
Needs to be rewritten the old-fashioned way: | ||
|
||
``` | ||
codeFor('breaking_change_bound_generator_function') | ||
``` | ||
|
||
</section> | ||
<section id="breaking-changes-classes"> | ||
|
||
### Classes are compiled to ES2015 classes | ||
|
||
ES2015 classes and their methods have some restrictions beyond those on regular functions. | ||
|
||
Class constructors can’t be invoked without `new`: | ||
|
||
```coffee | ||
(class)() | ||
# Throws a TypeError at runtime | ||
``` | ||
|
||
Derived (extended) class `constructor`s cannot use `this` before calling `super`: | ||
|
||
```coffee | ||
class B extends A | ||
constructor: -> this | ||
# Throws a compiler error | ||
``` | ||
|
||
Class methods can’t be used with `new` (uncommon): | ||
|
||
```coffee | ||
class Namespace | ||
@Klass = -> | ||
new Namespace.Klass | ||
# Throws a TypeError at runtime | ||
``` | ||
|
||
</section> | ||
<section id="breaking-changes-bare-super"> | ||
|
||
### Bare `super` | ||
|
||
Due to a syntax clash with `super` with accessors, bare `super` no longer compiles to a super call forwarding all arguments. | ||
|
||
```coffee | ||
class B extends A | ||
foo: -> super | ||
# Throws a compiler error | ||
``` | ||
|
||
Arguments can be forwarded explicitly using splats: | ||
|
||
``` | ||
codeFor('breaking_change_super_with_arguments') | ||
``` | ||
|
||
Or if you know that the parent function doesn’t require arguments, just call `super()`: | ||
|
||
``` | ||
codeFor('breaking_change_super_without_arguments') | ||
``` | ||
|
||
</section> | ||
<section id="breaking-changes-super-in-non-class-methods"> | ||
|
||
### `extends` for function prototypes, and `super` in non-class methods | ||
|
||
CoffeeScript 1.x allowed the `extends` keyword to set up prototypal inheritance between functions, and `super` could be used manually prototype-assigned functions: | ||
|
||
```coffee | ||
A = -> | ||
B = -> | ||
B extends A | ||
B.prototype.foo = -> super arguments... | ||
# Last two lines each throw compiler errors in CoffeeScript 2 | ||
``` | ||
|
||
Due to the switch to ES2015 `extends` and `super`, using these keywords for prototypal functions are no longer supported. The above case could be refactored to: | ||
|
||
``` | ||
codeFor('breaking_change_super_in_non-class_methods_refactor_with_apply') | ||
``` | ||
|
||
or | ||
|
||
``` | ||
codeFor('breaking_change_super_in_non-class_methods_refactor_with_class') | ||
``` | ||
|
||
</section> | ||
<section id="breaking-changes-dynamic-class-keys-exclude-executable-class-scope"> | ||
|
||
### Dynamic class keys exclude executable class scope | ||
|
||
Due to the hoisting required to compile to ES2015 classes, dynamic keys in class methods can’t use values from the executable class body unless the methods are assigned in prototype style. | ||
|
||
```coffee | ||
class A | ||
name = 'method' | ||
"#{name}": -> # This method will be named 'undefined' | ||
@::[name] = -> # This will work; assigns to `A.prototype.method` | ||
``` | ||
|
||
</section> | ||
|
||
<section id="breaking-changes-literate-coffeescript"> | ||
|
||
### Literate CoffeeScript parsing now more standardized | ||
|
||
In CoffeeScript 2’s parsing of Literate CoffeeScript this has been refactored to now be more careful about not treating indented lists as code blocks; but this means that all code blocks (unless they are to be interpreted as comments) must be separated by at least one blank line from lists. | ||
|
||
Code blocks should also now maintain a consistent indentation level—so an indentation of one tab (or whatever you consider to be a tab stop, like 2 spaces or 4 spaces) should be treated as your code’s “left margin,” with all code in the file relative to that column. | ||
|
||
Code blocks that you want to be part of the commentary, and not executed, must have at least one line (ideally the first line of the block) completely unindented. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,21 @@ | ||
### Bare `super` | ||
|
||
Due to a syntax clash with `super` with accessors, bare `super` no longer compiles to a super call forwarding all arguments. | ||
|
||
```coffee | ||
class B extends A | ||
foo: -> super | ||
# Throws a compiler error | ||
``` | ||
|
||
Arguments can be forwarded explicitly using splats: | ||
|
||
``` | ||
codeFor('breaking_change_super_with_arguments') | ||
``` | ||
|
||
Or if you know that the parent function doesn’t require arguments, just call `super()`: | ||
|
||
``` | ||
codeFor('breaking_change_super_without_arguments') | ||
``` |
14 changes: 14 additions & 0 deletions
14
documentation/sections/breaking_changes_bound_generator_functions.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
### Bound generator functions | ||
|
||
Bound generator functions, a.k.a. generator arrow functions, [aren’t allowed in ECMAScript](http://stackoverflow.com/questions/27661306/can-i-use-es6s-arrow-function-syntax-with-generators-arrow-notation). You can write `function*` or `=>`, but not both. Therefore, CoffeeScript code like this: | ||
|
||
```coffee | ||
f = => yield this | ||
# Throws a compiler error | ||
``` | ||
|
||
Needs to be rewritten the old-fashioned way: | ||
|
||
``` | ||
codeFor('breaking_change_bound_generator_function') | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
### Classes are compiled to ES2015 classes | ||
|
||
ES2015 classes and their methods have some restrictions beyond those on regular functions. | ||
|
||
Class constructors can’t be invoked without `new`: | ||
|
||
```coffee | ||
(class)() | ||
# Throws a TypeError at runtime | ||
``` | ||
|
||
Derived (extended) class `constructor`s cannot use `this` before calling `super`: | ||
|
||
```coffee | ||
class B extends A | ||
constructor: -> this | ||
# Throws a compiler error | ||
``` | ||
|
||
Class methods can’t be used with `new` (uncommon): | ||
|
||
```coffee | ||
class Namespace | ||
@Klass = -> | ||
new Namespace.Klass | ||
# Throws a TypeError at runtime | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
### Default values for function parameters and destructured elements | ||
|
||
Per the [ES2015 spec regarding function default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters) and [destructuring default values](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Default_values), default values are only applied when a value is missing or `undefined`. In CoffeeScript 1.x, the default value would be applied in those cases but also if the value was `null`. | ||
|
||
``` | ||
codeFor('breaking_change_function_parameter_default_values', 'f(null)') | ||
``` | ||
|
||
``` | ||
codeFor('breaking_change_destructuring_default_values', 'a') | ||
``` |
10 changes: 10 additions & 0 deletions
10
.../sections/breaking_changes_dynamic_class_keys_exclude_executable_class_scope.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
### Dynamic class keys exclude executable class scope | ||
|
||
Due to the hoisting required to compile to ES2015 classes, dynamic keys in class methods can’t use values from the executable class body unless the methods are assigned in prototype style. | ||
|
||
```coffee | ||
class A | ||
name = 'method' | ||
"#{name}": -> # This method will be named 'undefined' | ||
@::[name] = -> # This will work; assigns to `A.prototype.method` | ||
``` |
7 changes: 7 additions & 0 deletions
7
documentation/sections/breaking_changes_literate_coffeescript.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
### Literate CoffeeScript parsing | ||
|
||
CoffeeScript 2’s parsing of Literate CoffeeScript has been refactored to now be more careful about not treating indented lists as code blocks; but this means that all code blocks (unless they are to be interpreted as comments) must be separated by at least one blank line from lists. | ||
|
||
Code blocks should also now maintain a consistent indentation level—so an indentation of one tab (or whatever you consider to be a tab stop, like 2 spaces or 4 spaces) should be treated as your code’s “left margin,” with all code in the file relative to that column. | ||
|
||
Code blocks that you want to be part of the commentary, and not executed, must have at least one line (ideally the first line of the block) completely unindented. |
23 changes: 23 additions & 0 deletions
23
documentation/sections/breaking_changes_super_in_non_class_methods.md
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
### `extends` for function prototypes, and `super` in non-class methods | ||
|
||
CoffeeScript 1.x allowed the `extends` keyword to set up prototypal inheritance between functions, and `super` could be used manually prototype-assigned functions: | ||
|
||
```coffee | ||
A = -> | ||
B = -> | ||
B extends A | ||
B.prototype.foo = -> super arguments... | ||
# Last two lines each throw compiler errors in CoffeeScript 2 | ||
``` | ||
|
||
Due to the switch to ES2015 `extends` and `super`, using these keywords for prototypal functions are no longer supported. The above case could be refactored to: | ||
|
||
``` | ||
codeFor('breaking_change_super_in_non-class_methods_refactor_with_apply') | ||
``` | ||
|
||
or | ||
|
||
``` | ||
codeFor('breaking_change_super_in_non-class_methods_refactor_with_class') | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,43 +1,3 @@ | ||
## Unsupported ECMAScript Features | ||
|
||
There are a few ECMAScript features that CoffeeScript intentionally doesn’t support. | ||
|
||
<section id="unsupported-let-const"> | ||
|
||
### `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 doesn’t prevent the variable’s value from changing, the way constants usually do in other languages: | ||
|
||
```js | ||
const obj = {foo: 'bar'}; | ||
obj.foo = 'baz'; // Allowed! | ||
obj = {}; // Throws error | ||
``` | ||
|
||
</section> | ||
<section id="unsupported-named-functions"> | ||
|
||
### Named Functions and Function Declarations | ||
|
||
Newcomers to CoffeeScript often wonder how to generate the JavaScript `function foo() {}`, as opposed to the `foo = function() {}` that CoffeeScript produces. The first form is a [function declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function), and the second is a [function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function). As stated above, in CoffeeScript [everything is an expression](#expressions), so naturally we favor the expression form. Supporting only one variant helps avoid confusing bugs that can arise from the [subtle differences between the two forms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#Function_declaration_hoisting). | ||
|
||
Technically, `foo = function() {}` is creating an anonymous function that gets assigned to a variable named `foo`. Some very early versions of CoffeeScript named this function, e.g. `foo = function foo() {}`, but this was dropped because of compatibility issues with Internet Explorer. For a while this annoyed people, as these functions would be unnamed in stack traces; but modern JavaScript runtimes [infer the names of such anonymous functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) from the names of the variables to which they’re assigned. Given that this is the case, and given that not all functions in function expressions can be named (for example, the functions in `first.fn = ->; second.fn = ->` can’t both be named `fn`) it’s simplest to just preserve the current behavior. | ||
|
||
</section> | ||
<section id="unsupported-get-set"> | ||
|
||
### `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') | ||
``` | ||
|
||
</section> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
### `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') | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
### `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 doesn’t prevent the variable’s value from changing, the way constants usually do in other languages: | ||
|
||
```js | ||
const obj = {foo: 'bar'}; | ||
obj.foo = 'baz'; // Allowed! | ||
obj = {}; // Throws error | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
### Named functions and function declarations | ||
|
||
Newcomers to CoffeeScript often wonder how to generate the JavaScript `function foo() {}`, as opposed to the `foo = function() {}` that CoffeeScript produces. The first form is a [function declaration](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function), and the second is a [function expression](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/function). As stated above, in CoffeeScript [everything is an expression](#expressions), so naturally we favor the expression form. Supporting only one variant helps avoid confusing bugs that can arise from the [subtle differences between the two forms](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function#Function_declaration_hoisting). | ||
|
||
Technically, `foo = function() {}` is creating an anonymous function that gets assigned to a variable named `foo`. Some very early versions of CoffeeScript named this function, e.g. `foo = function foo() {}`, but this was dropped because of compatibility issues with Internet Explorer. For a while this annoyed people, as these functions would be unnamed in stack traces; but modern JavaScript runtimes [infer the names of such anonymous functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name) from the names of the variables to which they’re assigned. Given that this is the case, and given that not all functions in function expressions can be named (for example, the functions in `first.fn = ->; second.fn = ->` can’t both be named `fn`) it’s simplest to just preserve the current behavior. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.