Skip to content

Commit

Permalink
Update docs for classes, breaking changes (#4438)
Browse files Browse the repository at this point in the history
* Update classes docs for CS2

* Port breaking changes from https://github.com/jashkenas/coffeescript/wiki/%5BWIP%5D-Breaking-changes-in-CoffeeScript-2 into new docs section

* Update browser compiler

* Update re @connec’s notes; split classes section into two sections for classes and working with prototypes; make breaking changes examples editable whenever possible
  • Loading branch information
GeoffreyBooth authored Feb 9, 2017
1 parent ef1898b commit d1d2c16
Show file tree
Hide file tree
Showing 15 changed files with 868 additions and 495 deletions.
895 changes: 447 additions & 448 deletions docs/v2/browser-compiler/coffee-script.js

Large diffs are not rendered by default.

300 changes: 265 additions & 35 deletions docs/v2/index.html

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
self = this
f = -> yield self
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
f = (a = 1) -> a

f(null) # Returns 1 in CoffeeScript 1.x, null in CoffeeScript 2
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
A = ->
B = ->
B extends A
B.prototype.foo = -> A::foo.apply this, arguments
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
class A
class B extends A
foo: -> super arguments...
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class B extends A
foo: -> super arguments...
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
class B extends A
foo: -> super()
9 changes: 9 additions & 0 deletions documentation/examples/static.coffee
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
class Teenager
@say: (speech) ->
words = speech.split ' '
fillers = ['uh', 'um', 'like', 'actually', 'so', 'maybe']
output = []
for word, index in words
output.push word
output.push fillers[Math.floor(Math.random() * fillers.length)] unless index is words.length - 1
output.join ', '
105 changes: 105 additions & 0 deletions documentation/sections/breaking_changes.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
## 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.

### Function parameter default values

Per the [ES2015 spec regarding default parameters](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Default_parameters), default values are only applied when a parameter value is missing or `undefined`. In CoffeeScript 1.x, the default value would be applied in those cases but also if the parameter value was `null`.

```
codeFor('breaking_change_function_parameter_default_values', 'f(null)')
```

### 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')
```

### 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
```
### 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')
```

### `super` in non-class methods

In CoffeeScript 1.x it is possible to use `super` in more than just class methods, such as in manually prototype-assigned functions:

> ```coffee
A = ->
B = ->
B extends A
B.prototype.foo = -> super arguments... # Throws a compiler error
```
Due to the switch to ES2015 `super`, this is 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')
```

### 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`
```
15 changes: 5 additions & 10 deletions documentation/sections/classes.md
Original file line number Diff line number Diff line change
@@ -1,20 +1,15 @@
## Classes, Inheritance, and Super
## Classes

JavaScript’s prototypal inheritance has always been a bit of a brain-bender, with a whole family tree of libraries that provide a cleaner syntax for classical inheritance on top of JavaScript’s prototypes: [Base2](http://code.google.com/p/base2/), [Prototype.js](http://prototypejs.org/), [JS.Class](http://jsclass.jcoglan.com/), etc. The libraries provide syntactic sugar, but the built-in inheritance would be completely usable if it weren’t for a couple of small exceptions: it’s awkward to call **super** (the prototype object’s implementation of the current function), and it’s awkward to correctly set the prototype chain.

Instead of repetitively attaching functions to a prototype, CoffeeScript provides a basic `class` structure that allows you to name your class, set the superclass, assign prototypal properties, and define the constructor, in a single assignable expression.

Constructor functions are named, to better support helpful stack traces. In the first class in the example below, `this.constructor.name is "Animal"`.
CoffeeScript 1 provided the `class` and `extends` keywords as syntactic sugar for working with prototypal functions. With ES2015, JavaScript has adopted those keywords; so CoffeeScript 2 compiles its `class` and `extends` keywords to ES2015 classes.

```
codeFor('classes', true)
```

If structuring your prototypes classically isn’t your cup of tea, CoffeeScript provides a couple of lower-level conveniences. The `extends` operator helps with proper prototype setup, and can be used to create an inheritance chain between any pair of constructor functions; `::` gives you quick access to an object’s prototype; and `super()` is converted into a call against the immediate ancestor’s method of the same name.
Static methods can be defined using `@` before the method name:

```
codeFor('prototypes', '"one_two".dasherize()')
codeFor('static', 'Teenager.say("Are we there yet?")')
```

Finally, class definitions are blocks of executable code, which make for interesting metaprogramming possibilities. Because in the context of a class definition, `this` is the class object itself (the constructor function), you can assign static properties by using
`@property: value`, and call functions defined in parent classes: `@attr 'title', type: 'text'`
Finally, class definitions are blocks of executable code, which make for interesting metaprogramming possibilities. In the context of a class definition, `this` is the class object itself; therefore, you can assign static properties by using `@property: value`.
2 changes: 1 addition & 1 deletion documentation/sections/coffeescript_2.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@

CoffeeScript 2 generates JavaScript that uses the latest ES2015+ features. It is your responsibility to ensure that your target JavaScript runtime(s) support all these features, or that you pass the output through another transpiler like [Babel](http://babeljs.io/), [Rollup](https://github.com/rollup/rollup) or [Traceur Compiler](https://github.com/google/traceur-compiler). In general, [CoffeeScript 2’s output is fully supported by Node.js 7+](http://node.green/), although async functions require the `--harmony` or `--harmony-async-await` flags; and ES2015 modules require an additional transpiler. Output JavaScript intended for browsers generally requires additional transpilation.

If you’re looking for a single tool that takes CoffeeScript input and generates JavaScript output that runs in any JavaScript runtime, assuming you opt out of certain newer features, stick to the [CoffeeScript 1.x branch](v1/). CoffeeScript 2 [breaks compatibility](https://github.com/jashkenas/coffeescript/wiki/%5BWIP%5D-Breaking-changes-in-CoffeeScript-2) with certain CoffeeScript 1.x features in order to conform with the ES2015+ specifications, and generate more idiomatic output (a CoffeeScript `=>` becomes an ES `=>`; a CoffeeScript `class` becomes an ES `class`; and so on).
If you’re looking for a single tool that takes CoffeeScript input and generates JavaScript output that runs in any JavaScript runtime, assuming you opt out of certain newer features, stick to the [CoffeeScript 1.x branch](v1/). CoffeeScript 2 [breaks compatibility](#breaking-changes) with certain CoffeeScript 1.x features in order to conform with the ES2015+ specifications, and generate more idiomatic output (a CoffeeScript `=>` becomes an ES `=>`; a CoffeeScript `class` becomes an ES `class`; and so on).
7 changes: 7 additions & 0 deletions documentation/sections/prototypal_inheritance.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
## Prototypal Inheritance

In addition to supporting ES2015 classes, CoffeeScript provides a few shortcuts for working with prototypes. The `extends` operator can be used to create an inheritance chain between any pair of constructor functions, and `::` gives you quick access to an object’s prototype:

```
codeFor('prototypes', '"one_two".dasherize()')
```
6 changes: 6 additions & 0 deletions documentation/v2/body.html
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,9 @@
<section id="classes">
<%= htmlFor('classes') %>
</section>
<section id="prototypal-inheritance">
<%= htmlFor('prototypal_inheritance') %>
</section>
<section id="destructuring">
<%= htmlFor('destructuring') %>
</section>
Expand Down Expand Up @@ -95,6 +98,9 @@
<%= htmlFor('embedded') %>
</section>
</section>
<section id="breaking-changes">
<%= htmlFor('breaking_changes') %>
</section>
<section id="literate">
<%= htmlFor('literate') %>
</section>
Expand Down
8 changes: 7 additions & 1 deletion documentation/v2/sidebar.html
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,10 @@
<a href="#existential-operator" class="nav-link" data-action="sidebar-nav">Existential Operator</a>
</li>
<li class="nav-item">
<a href="#classes" class="nav-link" data-action="sidebar-nav">Classes, Inheritance, and Super</a>
<a href="#classes" class="nav-link" data-action="sidebar-nav">Classes</a>
</li>
<li class="nav-item">
<a href="#prototypal-inheritance" class="nav-link" data-action="sidebar-nav">Prototypal Inheritance</a>
</li>
<li class="nav-item">
<a href="#destructuring" class="nav-link" data-action="sidebar-nav">Destructuring Assignment</a>
Expand Down Expand Up @@ -80,6 +83,9 @@
</li>
</ul>
</li>
<li class="nav-item">
<a href="#breaking-changes" class="nav-link" data-action="sidebar-nav">Breaking Changes From 1.x</a>
</li>
<li class="nav-item">
<a href="#literate" class="nav-link" data-action="sidebar-nav">Literate CoffeeScript</a>
</li>
Expand Down

0 comments on commit d1d2c16

Please sign in to comment.