2013-02-08

CoffeeScript and me

I keep seeing comments like "CoffeeScript? Nah. I take my JavaScript black." I remember when I used to look at CoffeeScript with the same kind of superiority complex. I was happy with my JavaScript skills. The language was easy to use, and it would bend to my will quite well. It was comfortable. I could do a lot of work with JavaScript, and I did a lot of work. But then again, I was doing a lot of work... when I could be doing less.

At some point, writing lots of code (and sometimes clever code) gets old. It becomes a distraction, and it slows you down. You want to get things done fast, and express yourself without too much effort before the great idea vanishes from your L2 cache. Typing is just one aspect of this problem. Spending less time typing shortens the time it takes for your thoughts to appear in your code. Another aspect is how naturally you can express yourself in a given language. If the language resists your thoughts, you will spend too much time fighting it.

Both problems can be solved one way or the other. A great editor (like Vim) saves you a lot of keystrokes. For example, typing can be automated with snippets, macros, and code completion. Expressing yourself without too much resistance from the code is more personal: it depends on the way you think, and your previous experiences.

If you want to approach CoffeeScript as a JavaScript developer, keep in mind that CoffeeScript may solve these problems for you, and that that's sometimes more important than whether debugging it is easy, or whether you need to compile it down to JavaScript in order to run it. (I don't think debugging it is hard, though, nor that compiling it is too big of a problem.)

Typing less

CoffeeScript saves a lot of typing. There is no doubt about that. Remember how many times you had to write an anonymous function, and compare the syntax with CoffeeScript:

### JavaScript ###
function () { ... }

### CoffeeScript ###
-> ...

I know some might frown upon this. Some claim the -> is cryptic. It's mostly a matter of taste, and it doesn't take away from the fact that the syntax requires less keystrokes. There are also some cases where the opposite is true, like the ternary conditional expression:

### JavaScript ###
a ? b : c

### CoffeeScript ###
if a then b else c

Personally, I prefer the JavaScript version. Regardless, CoffeeScript version is more verbose. There is a good reason why the ternary conditional cannot be short, and that's because CoffeeScript has other uses for the question mark. Namely, it uses it for a few things that are much more common than the ternary (at least in my experience). For example:

### JavaScript ###
if (typeof a !== 'undefined' && a !== null) { ... }

### CoffeeScript ###
if a? ...

Another similar example is:

### JavaScript ###
if (typeof foo !== "undefined" && foo !== null) {
  foo.bar();
}

### CoffeeScript ###
foo?.bar()

In some ways, CoffeeScript is much like snippets you use in your editor. It just doesn't expand until compile time.

There are cases where reducing the amount of keystrokes isn't just a matter of speed. Sometimes, the extra keystrokes you have to make are simply unnecessary distractions. Curly braces come to mind. For example:

### JavaScript ###
myFunc(arg1, arg2, function(arg3) {
  ....
});

If you think about it, you have to open the brackets in order to list the arguments, and then you have another set of brackets that belong to the anonymous function, and finally a set of braces that also belong to the anonymous function. And on top of that, you have the semi-colon. Even the best editors I've used cannot help you with all of that. Some may get the brackets and braces right, but none get the semi-colon. Worrying about these things creates an unnecessary distraction. Meanwhile, this is what the code looks like in CoffeeScript:

### CoffeeScript ###
myFunc arg1, arg2, (arg3) ->
  ....

Clean and simple, and no extra braces to open or close, no semi-colons to forget.

Resistance to your way of thinking

Expressing yourself with least resistance from the language is a tricky problem to solve, and shortcuts, snippets, or macros, won't help with that. There has to be some connection between you and the language. In other words, the language must make sense to you. It's not CoffeeScript's fault if it doesn't make sense to you, but if it does, it will surely save you a lot of time over JavaScript.

Since it's mostly a perosonal matter, let me share what I find more natural in CoffeeScript.

How many times have you spent more than 10 minutes debugging code that was broken because of a missing variable declaration? Imagine what would happen if CoffeeScript didn't automatically declare variables in the correct scope:

### CoffeeScript ###
myfunc = ->
  if not foo?
    foo = document.getElementById('foo')

### JavaScript ###
var myfunc;

myfunc = function() {
  var foo;
  if (!(typeof foo !== "undefined" && foo !== null)) {
    return foo = document.getElementById('foo');
  }
};

Default values for function arguments:

### CoffeeScript ###
a = (foo='bar') ->
   alert(foo)

### JavaScript ###
var a;

a = function(foo) {
  if (foo == null) {
    foo = 'bar';
  }
  return alert(foo);
};

Splats that can consume arguments into arrays:

### CoffeeScript ###
a = (first, others...) ->
   alert(others[0])

### JavaScript ###
var a,
  __slice = [].slice;

a = function() {
  var first, others;
  first = arguments[0], others = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
  return alert(others[0]);
};

Array comprehensions:

### CoffeeScript ###
a = [
  {foo: 1, bar: 2}
  {foo: 3, bar: 5}
]

b = (i.foo + i.bar for i in a)

### JavaScript ###
var a, b, i;

a = [
  {foo: 1, bar: 2}, 
  {foo: 3, bar: 5}
];

b = (function() {
  var _i, _len, _results;
  _results = [];
  for (_i = 0, _len = a.length; _i < _len; _i++) {
    i = a[_i];
    _results.push(i.foo + i.bar);
  }
  return _results;
})();

And string interpolation, too:

### CoffeeScript ###
a =
  b: 1
  c: 2

# Note: multi-line string
alert "#{a.b} is 
#{if a.b < a.c then 'less than' else 'greater than'} 
#{a.c}" 

### JavaScript ###
var a;

a = {
  b: 1,
  c: 2
};

alert("" + 
a.b + 
" is " + 
(a.b < a.c ? 'less than' : 'greater than') + 
" " + 
a.c);

JavaScript is a fairly expressive language, and CoffeeScript doesn't take that away from you. It also adds quite a bit of new features that are not found in JavaScript. For me, this only increases the expressiveness, and allows me to get things done faster.

Conclusion

You might like your JavaScript black, and that's all fine. CoffeeScript is not JavaScript with milk, though. It's a different language that just happens to compile to JavaScript. It's not a JavaScript with milk, just as Python compiled to JavaScript doesn't make Python a JavaScript with milk. In my case, CoffeeScript has turned out to be a big time saver. Although it has its own quirks, when I look at the benefits rationally, I don't see why I would ever need or want to use JavaScript directly.