April 6, 2014

In Defense of Coffeescript

I often see arguments about whether or not using coffeescript is a good idea. Arguments against usually center around whether it’s a barrier for contributions, or whether it’s an unnecessary abstraction over another language that the developer needs to know anyhow.

I prefer writing Coffeescript to Javascript, and I use it whenever possible. In fact, my employer, Tapstream recently released a new frontend: an Ember.js application written entirely in coffeescript and mostly by me.

I believe that Coffeescript code is at least one of more succinct, more readable, and safer than equivalent Javascript code in just about any situation. Not only that, but Coffeescript helps you write correct Javascript code by default. Here are some of the ways that, in my opinion, Coffeescript helps you create better applications by avoiding common JS pitfalls.

Local scope by default.

If you don’t add a var, Javascript assumes you meant to make a global variable. This was sensible behavior in 1996 when you were writing mouseover scripts in the global scope, but it’s hard to imagine that it would be considered a good idea if Javascript were created, as a “real” programming language.

Of course, you can avoid this issue by always using var, and in so doing gain more control over your variables’ scope. But you’re not perfect, and you’ll sometimes forget a var. And when you do, javascript won’t be so kind as to warn you; things will work as expected, except for an unintentional global that can cause subtle bugs later.

Existence operator

There’s often discussion about whether Java permitting the existence of null was a good idea or not. But Javascript has not one, but two null values, and just about anything you do with that information that doesn’t involve treating them identically is a path to madness.

In Javascript, to check if a value is either of null or undefined, you can do this:

// Javascript

if(typeof myvar !== "undefined" && myvar !== null){
    // Do a thing
}

You can, but you won’t, because you’re not that disciplined. More likely you’ll fall back to if(myvar){} and hope there are no valid falsy values you forgot about (a more difficult question than it might be in a language with a simpler truth table).

Coffeescript can protect you from yourself with a simple mechanism: a new operator, ?, that checks for “existence” (i.e., not null or undefined). It looks like this:

# Coffeescript

if myvar?
    # Do a thing

You can even chain it, if nullability doesn’t upset you:

# Coffeescript

maybeVal = myObject?.myNestedObject?.myVal

This is roughly equivalent to

// Javascript

maybeVal = ((myObject || {}).myNestedObject || {}).myVal || null

Sensible Looping and Comprehensions

One of the most annoying parts about working with Javascript is writing for loops like it’s 1989. It’s not difficult, it’s just not necessary. Just compare:

// Javascript

for(var ii=0; ii<myArray.length; ii++){
    item = myArray[ii];
    // Do something with item
}

and

# Coffeescript

for item in myArray
    # Do something with item

There’s a lot less junk in the way, am I right? But what you may or may not have noticed is that the javascript contains a missing-var bug, which I chose not to correct after it emerged honestly while I was writing out that example.

Array comprehensions can help you take the readability and succinctness of your code one step further, for simple loops:

// Javascript

var myNewArray = [];
for(var ii=0; ii<myArray.length; ii++){
    myNewArray.push(modify(myArray[ii]);)
}

// Do something with myNewArray
# Coffeescript

myNewArray = (modify(x) for x in myArray)
# Do something with myNewArray

Note that my javascript example leaves something out: the coffeescript pops the for loop it compiles to inside a function, to keep the variable ii out of the current scope. I appreciate its consideration.

Default function arguments

Besides being shorter, there’s a safety aspect here, too; instead of this common pattern:

// Javascript

var myFunction = function(){
    arg1 = arguments[0] || "default";
    // Stuff
}

you can write:

# Coffeescript

myFunction = (arg1="default") ->
    # Stuff

An be protected in case arg1 is a falsy-but-valid value.

Browser compatibility

Javascript has a separate implementation in every browser. Coffeescript’s implementation depends only on the subset of javascript available to all common browsers, right down to IE6. That means you don’t have to worry about whether any of the features mentioned above work in a given browser; you can safely assume it. You still have to ensure that you only use libraries and functions that work with your target browsers, of course.

Bonus feature: automatic last-statement returns

This is hit-or-miss, but I really like it, so I wanted to include it. Implicitly returning the last statement à la Ruby or Lisp is a nice little encouragement to write code in small, composable functions. It’s not a gamechanger, but I like it anyhow.

These aren’t the only advantages Coffeescript gives you, they’re just the ones that feel to me like they genuinely improve the situation, instead of being simple syntactic sugar.

Like videos better?

Webucator.com has made available a video inspired by this post: