Why I'm (Finally) Switching to CoffeeScript

CoffeeScript Misconceptions

You may have already heard about CoffeeScript and some of the hype surrounding it but you still have found several reasons to not make the switch. This blog post is for you. Here are some of the reasons I held out for so long:
  • I wanted to understand Javascript and just didn't see how using a "simpler version" (my own thoughts) would make my life easier in the long run.
  • If I DID use an intermediate language, I wanted to be able to dump it at any time and not feel like I was forced to continue using it.
  • Putting one more thing with bugs in between myself and my code seemed fool hardy.
So here's the reasons I finally switched:
  • It's less verbose Javascript, not a different or simplified language.
  • A couple of shortcuts that enable you to use list comprehensions rather than error prone for statements.
  • CoffeeScript compiles to pretty awesome Javascript. I wouldn't have any concern dumping CoffeeScript at any time because of this. It would also have put some great conventions in my Javascript that I could follow.
  • Eli Thompson is always right. (You should read his blog. He's smart: http://eli.eliandlyndi.com/)
For-Loop Boiler Plate Banished

Here's an example of several Javascript for-loops embedded in a switch statement:

GNARLY! Now obviously we could clean this code up a bit... but seriously... 

Well let's just see that same code in CoffeeScript and how much better it can be:
That's the power of expressions.

Less Complex OO

Now how about classes? These are the bane of Javascript programmers everywhere. There are few right ways to do them and a billion wrong ways. CoffeeScript classes are the biggest simplification CoffeeScript makes to Javascript and was a big reason for my holding out for so long. Really though, they're just short hand that removes a bunch of boiler plate so I have less opportunity to introduce bugs. Here's a simple example: 

Simple Javascript class:

Same class in CoffeeScript:

Get Off My Lawn

In the past, people tried compiling to Javascript simply because they didn't get it. This is different. It's been over a decade since Javascript began to see wide use and enough of us get it now that we're starting to see tools that don't try to cover it up for being a broken language. Instead, we're seeing improvements made to a programming language we love and think can be even better. The only reason I see remaining to stick with Plain Old Javascript is nostalgia and fear of change.

I'll leave you with one last example. It's a full set of CoffeeScript that does drag/drop and zoom/pan in canvas. You can decide for yourself which version of the code you'd rather work on.

Before CoffeeScript:

After CoffeeScript:
18 responses
At least the first example is horrible. You could easily replace the first two examples with something like the following, using MooTools, but easily ported to another js lib.

// First example
var keydown_action_map = {
37: 'pan_left',
38: 'pan_up',
39: 'pan_right',
40: 'pan_down',
189: 'zoom_out',
187: 'zoom_in'
}
document.addEvent('keydown', function(event) {
var action = keydown_action_map[event.keyCode];
game_pieces.each(game_piece[action], game_piece);
});

// Second example
var foo = new Class({
initialize: function(param1, param2) {
alert("I've been constructed!");
},
bar: function() {
return it.shake_like(a_polaroid_picture);
}
});

@reaktivo: I don't at all mean to say there is no way to make JS better in JS. Whether you use a framework, code you wrote, or a compiler it's all roughly equivalent. A nicety of CoffeeScript is that I can also rid myself of those damn braces and semi-colons. Also closure syntax is much less noisy. This is a way that feels very good to me.
I agree that Coffeescript is a very interesting technology, but i do have the feeling that many comparisons are not very realistic because articles are comparing Coffeescript with compiled Javascript-from-Coffeescript.

I don't know Coffeescript wel enough, but i don't see anything in this article that can't be done when using a library such as Underscore, Spine or jQuery. For example, the the first example could be written in just slightly more LOC like this:

document.onkeydown = function(event) {
var actions = {
37 : "pan_left",
38 : "pan_up",
39 : "pan_right",
40 : "pan_down",
189 : "zoom_out",
187 : "zoom_in"
};

var action = actions[event.keyCode];

_.each(game_pieces, function(game_piece) {
game_piece[action]();
});

return the_screen.refresh(game_pieces);
}

@huskyr Who said the bulk of this couldn't be done some other way? Also, I enjoy the new function syntax and removal of the braces and semi-colons. That's the fine line that makes this the way for me to go.
Don't use for loops in JS unless you really have to... JS now has map/forEach much nicer... and for crapy old browsers you have backwards compatible functions you can use. see https://gist.github.com/1195667
One of my biggest gripes with CofeeScript, is the outputed Javascript. As shown by @reaktivo above simple Javascript code is often a lot smaller then the converted CofeeScript to Javascript code.

Ultimately people seeing the compiled Javascript code assume CofeeScript is instantly better(due to CofeeScript bing smaller).

CofeeScript has nice features, but you really need to know Javascirpt before learning CofeeScript. It in many ways just adds more abstraction for already confused users.

You do definitely still need to know Javascript. CoffeeScript isn't a beginner enabler at all. I totally agree with you Justin.
I've been coding Javascript for a few years now (actually, it's 13 years -- yikes) and I'm struggling to get excited about coffee script. It's another syntax to learn, and it feels a bit like another 'flavour of the month' (though I don't doubt it'll get enough traction to stick around). I do quite like plain old Javascript. It's enough like C/C#/Java that it's familiar, and I actually like the braces and semi-colons. If CoffeeScript were pure Ruby, converted to JS, I'd probably jump on it in an instant, but I just can't be bothered learning a new syntax to save a few lines of whitespace and not have to write for loops (especially because map/each/whatever already work better than for...).

I don't know. I appreciate this article, because it's nice to see code and compare the difference, but I still don't think I'll switch yet...

Bad CoffeeScript code will compile into bad JavaScript code. Your first example illustrates this beautifully. (Sorry!) The reason the JavaScript code is so bulky and repetitive is that the *CoffeeScript* code is just as repetitive.

Try writing the CoffeeScript code like this instead:

keyMoves =
37: 'pan_left'
38: 'pan_up'
39: 'pan_right'
40: 'pan_down'
187: 'zoom_in'
189: 'zoom_out'

document.onkeydown = ( event ) ->
move = keyMoves[event.keyCode]
piece[move]() for piece in game_pieces
the_screen.refresh( game_pieces )

That compiles to *much* better JavaScript:

var keyMoves;
keyMoves = {
37: 'pan_left',
38: 'pan_up',
39: 'pan_right',
40: 'pan_down',
187: 'zoom_in',
189: 'zoom_out'
};
document.onkeydown = function(event) {
var move, piece, _i, _len;
move = keyMoves[event.keyCode];
for (_i = 0, _len = game_pieces.length; _i < _len; _i++) {
piece = game_pieces[_i];
piece[move]();
}
return the_screen.refresh(game_pieces);
};

Cutting out the repetition in the CoffeeScript code has the same benefit - and even more so - in the generated JavaScript. In fact, this generated JS is almost identical to the examples posted by other commenters, except it uses a conventional for loop instead of a library's iterator function.

Personally I would write a no-library version of the JavaScript this way:

keyMoves = {
37: 'pan_left',
38: 'pan_up',
39: 'pan_right',
40: 'pan_down',
187: 'zoom_in',
189: 'zoom_out'
};

document.onkeydown = function( event ) {
var move = keyMoves[event.keyCode];
for( piece, i = -1; piece = game_pieces[++i]; )
piece[move]();
the_screen.refresh( game_pieces )
}

This style of for loop is less common but very useful when the array is not sparse (and we know from the original code that game_pieces is not sparse, otherwise it would crash on a null reference).

Here's another bit of simplification. Take these three methods on the last example:

interact_at: (x,y)->
if @held_item != null
@drop_tile_if_over_it(x, y)
else
@pick_up_tile_if_over_it(x, y)
drop_tile_if_over_it: (x,y)->
for game_piece in @game_pieces
if game_piece.is_at x, y
@held_item = null
break;
pick_up_tile_if_over_it: (x,y)->
for game_piece in @game_pieces
if game_piece.is_at x, y
@held_item = game_piece
@held_item.start_dragging x, y
break;

I'm guessing that the last two methods are only used by the first one. In that case, you could shorten the code to:

interact_at: (x,y)->
for game_piece in @game_pieces
if game_piece.is_at x, y
if @held_item
@held_item = null
else
@held_item = game_piece
@held_item.start_dragging x, y
break

Even if you needed the other two methods outside the class, you could still make it much simpler than the original.

One other suggestion: in both CoffeeScript and JavaScript, it's more idiomatic to use camelCaseNames for variables and functions instead of names_with_underscores.

Finally, the last JS example is labeled "Before CoffeeScript", but isn't this *compiled from* CoffeeScript code just like the other examples? :-)

Haha! Thanks Michael!

To your last point: Touche. I was lazy. :)

To the rest of your points: I appreciate your input. Pair programming FTW!

If anything, the game loop/switch is a good example of how badly CoffeeScript writes the final JS. Seriously, why all those different variables for the same loop?!
Instead of ......

if @held_item != null
@held_item.drag_to(x, y)

..... you could write....

@held_item?.drag_to(x, y)

.... but the resulting JS might not be so tidy

@Jason: That is hawt. Thanks!
Why the fuck so many people feel urged to extract something good from CoffeeScript's retarded ideology? I feel like node.js has brought us the same crap what PHP did several years ago. Different language, same poor code.
In real-life projects, introducing CoffeeScript in your stack is going to bring a lot of complexity for both the tech (you need to compile the code) and people (they need to be fluent in both CS and JS). In my experience, it's very rarely worth the effort. By using CoffeeScript you're ALWAYS making your project much less accessible, and usually for no practical benefit.

And that's a problem with a lot of new tools and pseudo standards nowadays. They don't really focus on accessibility at all. I similarly tend to avoid HAML and all esoteric templating languages. LESS/SCSS are an example where the usefulness, I think, outweigh the disadvantages of introducing an abstraction on top of the core language (CSS), although I've seen that it takes discretion from the users to not create incomprehensible stacks of endless mixin hierarchies. I'm pretty excited about TypeScript since this aspect is much better taken care of there.

And btw. I hate CoffeeScript's syntax, it's very unintuitive for me. I could get used to it if I didn't, in real life, always have to deal with JavaScript simultaneously.

3 visitors upvoted this post.