BT

Facilitating the Spread of Knowledge and Innovation in Professional Software Development

Write for InfoQ

Topics

Choose your language

InfoQ Homepage News CoffeeScript - JavaScript the Good Parts

CoffeeScript - JavaScript the Good Parts

This item in japanese

At the recent Emerging Languages Conference (a part of OSCON), Jeremy Ashkenas the lead developer of DocumentCloud and creator of underscore.js, presented CoffeeScript, a language that is cross compiled to JavaScript.

Just today CoffeeScript version 0.9.0 was released. The main, compatibility breaking change was to change the assignment operator from colon : to the more JavaScript like equals sign =. This very much discussed step was mainly done to enable YAML style object literals and named parameters. Half assignments (a : or 'default') were also removed from the language. Some improvements have been introduced to the (optional) class inheritance system.

There are other such languages, but as we'd like to cover here, CoffeeScript differs in intent and features. Jeremy provided many insights in answering our questions. His answers are reflected in the article.

Jeremy worked extensively with JavaScript and experienced its shortcomings firsthand. He sums up the intent behind his language:

CoffeeScript is a simple thought experiment to imagine a language that exposes a minimal syntax for the beautiful object model that underlies JavaScript. There are three main aspects to doing that: Having a lighter syntax, cleaning up the semantics of broken JavaScript constructs, and providing bonus language features as shorthand for common JavaScript patterns. CoffeeScript's target audience is folks who want to write readable code that runs in the browser, and want to avoid the dark alleys of JavaScript while embracing the good parts.

 

With the recent introduction of powerful JS engines (such as V8 and Nitro) JavaScript became a very fast and powerful dynamic language. Its omnipresence in web applications and recently in event driven, non-blocking server runtimes (such as Node.js) makes it a critical language of the near future. Besides performance and familiarity with the language, a new factor is the reuse of JavaScript code and libraries on client and server. Especially the domain model, validations and application logic can be shared.

Jeremy is very clear on that: "The first person to create a pleasant end-to-end system for programming JavaScript web applications wins the next five years of web development, period."

These reasons made it obvious for Jeremy to focus on JavaScript as target platform. While based on JavaScript, CoffeeScript is heavily influenced by Python, functional languages like Haskell and of course EcmaScript 5 and many of the suggestions from the EcmaScript Harmony Wiki. The three main areas that CoffeeScript focuses on are:

Syntactic cleanup

  • Python style significant whitespace
  • implicit parentheses
  • no semicolons
  • String continuations
  • concise function literals
  • YAML style object literals

Semantic enhancements

  • everything is an expression (returns a value)
  • all variables in local lexical scope, no pollution of global scope
  • simple assignment and variable declarations, destructuring assignments
  • switch statements compiled to if-then-else chains
  • chain comparisons
  • named parameters

Goodies

  • variable arguments lists (splats)
  • literate programming (write the code within its documentation)
  • pythons range, array and object comprehensions
  • existential (elvis) operator
  • explicit strong binding of current self to function with => Hashrocket operator
  • fast and working class based inheritance support, based on the google.inherit approach
  • support for static inheritance and automatic delegation to superclass methods
  • heredocs, multiline strings, literal regexps, string interpolation/substitution
  • Cake a simple build system similar to Rake
  • <script type="text/coffeescript"> tags, minified coffescript compiler for inline use

Some examples taken from the documentation show the features.

# Assignment:
number   = 42
opposite = true

# Conditions:
number = -42 if opposite

# Functions:
square = (x) -> x * x

# Arrays:
list = [1, 2, 3, 4, 5]

# Objects:
math =
  root:   Math.sqrt
  square: square
  cube:   (x) -> x * square x

# Named (like) parameters
fun key : value 
(compiled to call({key: value}); )

# Splats:
race = (winner, runners...) ->
  print winner, runners

# Existence:
alert "I knew it!" if elvis?
# Accessor existence operator (null safe)
lottery.drawWinner()?.address?.zipcode

# Array comprehensions:
cubes = math.cube num for num in list

# Object comprehensions:
yearsOld = max: 10, ida: 9, tim: 11
ages = for child, age of yearsOld
  child + " is " + age

# Destructuring
[city, temp, forecast] = weatherReport "Berkeley, CA"
[open, contents..., close] = "".split("")
     
     # Functions and strong binding of this
     Account = (customer, cart) ->
       @customer = customer
       @cart = cart
     
       $('.shopping_cart').bind 'click', (event) =>
         @customer.purchase @cart
     
     # Regexp & String substitution
     sep =   "[.\\/\\- ]"
     dates = /\d+#sep\d+#sep\d+/g
     

Coffeescript can be installed by cloning the github repository and using the included build system Cake (similar to Rake) to build it (sudo bin/cake install). With npm, the Node Package Manager it is equally easy: sudo npm install coffee-script. Then the coffee compiler is available to compile CoffeeScript to JavaScript or execute it interactively.

coffee is a self hosted CoffeeScript compiler:

The trick with a self-hosted language is that you have to start with a place to stand. The original CoffeeScript compiler was written in Ruby. With 0.5.0, I did a fairly one-to-one port of the Ruby version to CoffeeScript, compiled that, ran the new compiler on it's own code, and then ran all of the tests with the self-compiled version. A heart-stopping moment, for sure. [...] Doing a self-hosting compiler keeps you honest. You stay sensitive to corner-case bugs, performance, and the cleanliness of the generated code.

 

As CoffeeScript is compiled source to source to JavaScript, some language features that have been requested (like negative array indexing) are not possible. At least not with access to the JS runtime.
Another aspect of cross compilation are runtime error traces and debugging the generated JavaScript. As line numbers won't match it is more difficult to relate the JavaScript code to the original CoffeeScript. That's why Jeremy took special care to create well readable JavaScript code and also suggests compiling beforehand and deploying/debugging the JS code directly. So CoffeeScript works as a code generator language.

Regarding the effort of creating CoffeeScript, Jeremy notes that it is no rocket science:

CoffeeScript is only 2,090 lines of code, all of it annotated, literate-programming-style. If you want to get your feet wet with a programming language that fits the way you want to code, I encourage you to borrow a runtime that you like, and to play with the source of some of the languages presented at the camp. Let a thousand little languages bloom.

A rich ecosystem has already evolved around CoffeeScript. Various commiters provided syntax highlighters for different editors and integration projects for node.js, Rhino, Rack, Python, Rails3 and Jammit.

You can listen to Jeremy talking about CoffeeScript at the TheChangeLog podcast episode 0.2.9 and the JSConf2010 presentation.

Rate this Article

Adoption
Style

BT