July 15th, 2013
CS adds a lot of syntactic sugar and some of it is on top of JS's prototypes where it creates a clean and effective way of inheriting prototypes. If there is one feature in CS I would emphasize as being awesome, it is the addition of a properly functioning
CS adds language level syntax for binding a function to a context
=> eliminating the need for library level shims such as underscore's _.bind and the line. It's an effective way to eliminate an extra method call or manual variable assignment.
It adds simplifying syntax helpers such as
unless. These help smooth out the language, make it more usable, less verbose and easier to read. It has a bunch of syntax sugar which JS desperately needed and as a Ruby dev I always found I wanted.
CS subtly (and not so subtly) changes the meaning of several core pieces of JS. The most notable examples during my weeks using it were the assumption of local scope, and the global substitution of
The assumption of local scope is a fantastic idea for JS. If you define a variable, 99% of the time you want it only in the method or script where you define it, but bare JS assumes that if you didn't put
var in front of it, you wanted it globally. CS makes the more rational assumption that you wanted it locally. This can be slightly annoying in the case of defining classes, where it still makes this assumption. I can easily see an argument for consistency over shortening the syntax by a few
window. lines, so I'm not up in arms over it.
I had one major concern of the debuggability going in to using CS. In the end, this concern was moot. CS's generated code closely resembles your original and telling where each line came from is quite easy. For those more concerned there is the option of turning on source maps, which allow your debugging environment to link the js source with cs source. I think this was also mitigated by the fact that I already code in small, maintainable modules which are well-namespaced (as well as you can in JS).
The substitution of all
=== is similar. 90% its what you want, but the rest of the time when you were expecting a coercive check it can bite you. Being aware of it solves most of the cases, but it also causes corner cases.
With CS's assumption of non-coercive checks for all your equality checks. If you want a coercive check, for instance you have a select drop down that has the id in the value field, but the id is stored as an integer in your models, you have to escape the check and it will be injected as pure JS. This is fairly easy utilizing backticks. No problem, right?
No problem. Until you use the aforementioned
=>. CoffeeScript achieves the binding effect by setting a variable of
_this and replacing your calls to
_this. Unfortunately, if you use backtick escaping, it doesn't replace your
this and you have to manually change your reference to
_this inside the backticks. Annoying.
What do you tell CoffeeScript when you have a bloody finger? Nothing you didn't already tap tab a thousand times to tell it.
CoffeeScript is worth using. But the first person to fork it and give me Ruby style block syntax gets a parade and a holiday named after them.