2011-01-14

CoffeeScript versus paren-free JavaScript

CoffeeScript is a new syntax for JavaScript. The idea is to fix some of JavaScript’s deficiencies while staying so close to it that one can handle the “compiled version” in an emergency. I like the idea, but not all of it is an improvement. This post will first critique CoffeeScript and then present Brendan Eich’s simplified “paren-free JavaScript”.

A word about conciseness

When it comes to conciseness, we have to distinguish between the writer having to type less and the ease with which the reader can decipher something. Sometimes writing less makes things harder to decode. For example, most words are read by humans as single tokens, so using less characters for a word does not help. Familiarity is also important. If something familiar is used all of the time, it trumps a small percentage being replaced by something more concise.

CoffeeScript

Check out CoffeeScript’s excellent website to get more details and see how the examples below are translated to JavaScript.
    # Assignment:
    number   = 42
    opposite = true
OK, there are no semicolons. Cool. Not. Why are people so obsessed with eliminating semicolons? This happens in the Java community, too (Groovy). Humans are used to punctuation (=good for the reader) and the writer only saves a single character per line.

The above example shows that there is no var in CoffeeScript and variables are automatically declared. But having to declare variables is one of JavaScript’s best features, because it catches typos. As an aside, var will soon be improved as the block-scoped let.

    # Conditions:
    number = -42 if opposite
This kind of if statement Reminds me of Perl. It avoids the familiarity of if plus block (which one should always use in JavaScript), without helping readers much.
    # Functions:
    square = (x) -> x * x
The current function definitions are quite verbose. Thus, a short function notation is very useful, especially whenever a function is an argument of another function: callbacks, custom looping constructs etc. I’m not especially fond of the syntax, because it looks un-JavaScript-like but there are unfortunately many constraints placed on a shorter function notation: You cannot put a legal identifier in front of parentheses, because that would be interpreted as a function call. That precludes shorter names for the function operator (function is not a legal identifier) such as fn, but also the legal identifiers λ and ƒ.
    # Arrays:
    list = [1, 2, 3, 4, 5]
    
    # Objects:
    math =
        root:   Math.sqrt
        square: square
        cube:   (x) -> x * square x
The object syntax brings no improvement and introduces a Python-like style. Mixing styles is not a good idea.
    # Splats:
    race = (winner, runners...) ->
        print winner, runners
Yes. Better parameter declarations for functions. ECMAScript.next [2] might have them, maybe even named/keyword parameters (details). Named parameters are awesome. Python is exemplary in how it handles parameters.
    # Existence:
    alert "I knew it!" if elvis?
The question mark operator ? is not much of an improvement compared to using a normal if and a function:
    if (defined(elvis)) { ... }
But this operator can be used with a dot to safely construct property chains which is truly useful (drawWinner and address can be null, in which case the result zip is null):
    zip = lottery.drawWinner?().address?.zipcode
Array comprehensions are cool:
    cubes = (math.cube num for num in list)
Additional features of CoffeeScript:
  • Array slicing and splicing
  • Everything is an expression (especially if statements) – man do I miss this from functional languages
  • Classes, inheritance, super calls.
  • Destructuring assignment. Yes, as seen in Python, functional languages, etc.
  • Extended regular expressions (with whitespace and comments) – absolutely needed
  • And more (some of it adds unnecessary clutter and differences with JavaScript)

Paren-free JavaScript

This is a simpler syntax for JavaScript, as proposed by Brendan Eich. (There is much more about JavaScript’s future in the article, check it out.)
    if year > 2010 {
        syntax++
    }
    
    for i in iter {           // i is a fresh let binding!
        frob(i)
    }
    
    while lo <= hi {
        let mid = (lo + hi) / 2
        // binary search blah blah blah
    }
    
    ... return [i * i for i in range(n)]   // array comprehension
Note that the paren-free for-in also has better semantics: It supports iterators and generators. And it changes array iteration to be over values, not keys. These features combined allow one to implement new kinds of iterations: For example, the following code uses a hypothetical helper function keys() that returns an iterator over the names of both own properties and properties inherited via the prototype chain. This is how for-in currently works; call it a legacy mode. In contrast, the paren-free for-in iterates only over own property names of objects.
    for k in keys(obj) {
        // k is a string-typed key
    }
Another possibility is to iterate over properties as (key,value) pairs:
    for [key,value] in items(obj) {
    }
Two more points:
  • Mandatory blocks: paren-free syntax makes blocks (as opposed to single statements) mandatory. Quote:
    You need to mandate either parens around the head, or braces around the body [...]. So C requires parens around head expressions. But many style guides recommend always bracing, to ward off dangling else. Go codifies this fully, requiring braces but relieving programmers from having to parenthesize the head expression.
    This is a good call. It will lead to cleaner and more uniform JavaScript code.
  • Migration: Eich suggests to make for-in syntax with parens an error. Then migrating to the new syntax incurs initial costs. But it also lets one detect incompatible code early on and makes the overall semantics simpler (than if compatibility was preserved).
Related posts:
  1. Brendan Eich’s dream for the next version of JavaScript
  2. ECMAScript.next features are taking shape
  3. Google’s Traceur: compile ECMAScript.next to JavaScript on the fly

No comments: