My biggest problems with CoffeeScript has been with indentation, which is no surprise, given the basic value proposition of the language. There are places where I've accidentally deleted a single space and completely changed the meaning of my code.
Now, notice what happens when we delete a single space.
The change in indentation confused the CoffeeScript compiler; it ended the call to
View.extend() and created a new expression for an object literal that is created and thrown away.
Part of my solution to this class of issue, in Emacs, is to automatically increase the font size when editing CoffeeScript files. I may have to consider a switch from spaces to tabs as well, something that I've never considered in the past. I've also noticed that some IDEs, including IntelliJ, draw a vertical line to connect code at the same indentation layer. I don't have enough Emacs hacking experience to accomplish that, but I hope someone does.
Another problem I've hit is with function invocation; CoffeeScript style is to omit the parenthesis following the function name, and just immediately start listing function parameters:
element.setAttribute "width", "100%"
However, if your API allows chaining, you may be tempted to:
element.setAttribute "width", "100%".setAttribute "color", "blue"
.setAttribute binds to the immediate value, the string:
element.setAttribute("width", "100%".setAttribute("color", "blue"));
One option is to enclose the first call with parenthesis:
(element.setAttribute "width", "100%").setAttribute "color", "blue"
I want to like that option, as it stays consistent with the normal format for function invocation; it just captures the result for chaining. However, each additional
setAttribute() call will require an additional nesting layer of parenthesis. This leaves the following as the solution:
element.setAttribute("width", "100%").setAttribute("color", "blue")
And now we are stuck having to parse two different syntaxes for function invocation, depending on some very specific context.
Another issue is that, once you start using the standard function invocation style, which doesn't use parenthesis, you can easily get tripped up:
is null bound tightly to the
"div" string literal; the result (true or false) was passed to the
find() method, rather than the expected
What's interesting is that the above concerns aside, most of the time my first pass at the CoffeeScript does produce exactly what I'd expect, making me feel silly to waste the time to check it! Other times, I find that my first pass is actually too verbose, and can be simplified. Here is an example from some code I've written for Tapestry, a simple DSL for constructing DOM elements on the fly:
This is invoking the
Even getting rid of the commas is allowed. The commas are equivalent to the line break and indentation that's already present:
And that's where I start really liking CoffeeScript, because quite often, the code you write looks very close to a bespoke DSL.