You're Welcome, JavaScript (Signed, CoffeeScript)
At Panda Strike, we’ve gone on the record in our preference for using CoffeeScript. Recently, as developers have begun preparing for ES6, we’ve seen a few blog posts suggesting that CoffeeScript has served its purpose. We don’t agree; in fact, we believe CoffeeScript is more relevant than ever.
CoffeeScript Is a Real Programming Language You Can Use
Let’s start with the tacit premise of many of the arguments against CoffeeScript: that it isn’t a real programming language. This reduces CoffeeScript to a mere preprocessor, due to its dependence on JavaScript. Of course, this is irrelevant when it comes to its status as a language. Just because JavaScript is the compile target doesn’t prevent, say, one of the primary contributors to the project from implementing an alternative compiler that can target different backends. I mean, CoffeeScript has a grammar and everything!
I think some of this perception comes from the design goals (“it’s just JavaScript”), but that is just about the semantics of the language. It doesn’t mean it’s not a language. In fact, when I’m developing in CoffeeScript, I’m hardly aware of the generated code, any more than I was back in the day when coding in C would occasionally find me staring at a bunch of assembly code in gdb
.
The burden of proof here does not lie with the developers choosing to use CoffeeScript (or TypeScript or PureScript or React). CoffeeScript does not require an existential justification, any more than the use of JavaScript does, or C, or Go, or Java, or any other language, all of which are necessarily compiled into a different form prior to execution. As compile targets go, JavaScript is pretty cool, since it already runs on just about every computer in the world. In other words, JavaScript has achieved the original ambition of Java bytcode. Nice!
The Learning Curve is Flattening
We’re happy to see the obvious influence CoffeeScript has had on the nascent ES6 standard. Not only does this demonstrate the value of the project, but it shortens the learning curve for people coming to CoffeeScript from JavaScript, and vice-versa. JavaScript now has classes, string interpolation, splats, array and object destructuring, and shorthand for functions, features that CoffeeScript has had for years. JavaScript developers can now stop complaining so much about how they can’t make sense of CoffeeScript code. With ES6, if you can’t understand CoffeeScript, you’re probably going to struggle with JavaScript, too.
CoffeeScript Works Great With ES6
There seems to be some FUD about CoffeeScript requiring major changes because of ES6. This is funny, not only because many of those changes involve incorporating CoffeeScript features into JavaScript, but because ES6 is a superset of ES5, meaning that it’s impossible for CoffeeScript code to break because of ES6. In fact, we’ve been using CoffeeScript with ES6 for months with no problems. This is reminiscent of the FUD that you can’t use JavaScript libraries with CoffeeScript. Again, CoffeeScript compiles into ES5, and ES6 is backward compatible with ES5, so it’s literally impossible for CoffeeScript to cause problems interoperating with JavaScript, ES5 or ES6.
The real issue here is whether you care whether the generated JavaScript itself takes full-advantage of ES6 features. And, for CoffeeScript developers, the answer is almost always going to be no. Why? Because we’ve already had these features for years. It’s like asking whether you’re going to stop using your favorite JavaScript libraries because they didn’t rewrite their code to use classes. But even that isn’t an accurate analogy, because many, perhaps most, ES6 features, like generators and proxies, can be used in CoffeeScript with little or no changes to the language—let alone changes that break existing code.
Yes, there may an edge case here or there that requires CoffeeScript to evolve. Those, however, are dwarfed by the changes between ES5 and ES6 in JavaScript itself. Every JavaScript library, every JavaScript runtime, and, probably most importantly, every JavaScript developer will be profoundly affected by those changes. Pretending like CoffeeScript is somehow uniquely sensitive to them is cherry-picking.
CoffeeScript Is Still the Better Language…
Of course, better is subjective. That said, CoffeeScript continues to be, far and away, a more expressive language than JavaScript. (And, yes, generally more concise code is more expressive and thus more powerful.) Fortunately, the people defining ES6 understand this, and they’ve incorporated as much of CoffeeScript into JavaScript as possible. But they can only go so far without breaking ES5 code. Simply put, even the people designing the JavaScript language realized that CoffeeScript was a better language.
And it remains so, not through any fault of the people who have worked so hard to bring us ES6 (which is a great step forward), but because of the billions of dollars’ worth of ES5 code that’s already deployed. The need for parenthesis and curly braces everywhere, by itself, makes JavaScript code harder to read and maintain. Similarly, generator functions still require the function
keyword. CoffeeScript, meanwhile, elegantly converts functions containing a yield
expression into generators for you. Contrast these two Fibonacci generators.
CoffeeScript
fib = do (s=[0,1], first, second) ->
->
while true
[first, second] = s
s.push first + second
yield s.shift()
JavaScript
function* fib() {
let s = [0, 1], first, second;
while (true) {
[first, second] = s;
s.push(first + second);
yield s.shift();
}
}
That’s six lines versus eight lines, or 1/3rd again as much code. Of course, the two extra lines are just closing curly braces. But even if we look at character counts, it’s a 12% increase in an example that takes full advantage of ES6.
How about a Stack class?
CoffeeScript
class Stack
constructor: (@data=[]) ->
push: (value) -> @data.push value
pop: -> @data.pop()
peek: -> @data[0]
JavaScript
class Stack {
constructor() { this.data = []; }
push(value) { return this.data.push(value); }
pop() { return this.data.pop(); }
peek() -> { return this.data[0]; }
}
We’ve gone one extra line for the trailing curly brace, but, in terms of character count, the ES6 JavaScript requires 46% more code. The CoffeeScript code is just more concise and easier to scan.
The gap may have narrowed, but it’s still there.
…Especially For Functional Programming
Embedded within JavaScript is a nice functional programming language. CoffeeScript makes this language much more accessible. And that’s unchanged by ES6. Sure, the introduction of the =>
operator helps, but that also binds this
which introduces unnecessary overhead (and a possibly undesirable side-effect). In addition, JavaScript requires explicit returns and the usual accompaniment of readibility-impairing parenthesis and curly braces. Consider a library like funcoffee. Almost every function in the library can be a one-liner in CofffeeScript. In JavaScript, these would frequently need to split on three lines.
For example, here’s the definitions for partition
:
CoffeeScript
partition = curry (f, xs) -> [filter(f, xs), reject f, xs]
JavaScript
var partition = curry(function(f, xs) {
return [filter(f, xs), reject(f, xs)];
});
The JavaScript version isn’t terrible. But I think the reason a more functional style hasn’t taken hold in JavaScript in the first place is that it just isn’t quite concise enough. CoffeeScript crosses some invisible threshold that makes a functional-style practical.
CoffeeScript Doesn’t Exclude Developers
I keep seeing variations of the argument that using CoffeeScript excludes JavaScript developers, but not vice-versa, since most CoffeeScript developers know JavaScript. In the context of ES6, the argument goes on to say, basically, “…and now that ES6 has all the goodness of CoffeeScript, it’s not worth excluding anyone.” This is known as the bandwagon fallacy and ignores the fact that a large part of the reason that ES6 has all these features in the first place is because large numbers of developers adopted CoffeeScript. That would have never happened based on bandwagon reasoning.
Choosing any language excludes developers. Using Ruby tends to put off Python programmers. Using C++ puts off systems programmers who prefer the relative simplicity of C. And, sure, using CoffeeScript puts off some subset of JavaScript programmers. And guess what? Using JavaScript tends to put off some CoffeeScript programmers, too. In fact, this argument applies to the libraries you use, too. Or which platforms or browsers you target.
Do you want an innovation-stifling monoculture? Don’t answer that—it’s a rhetorical question. You’re not going to get one, regardless. There are lots of languages and libraries and platforms and lots more coming. Deal with it. JavaScript is a better language because a lot of developers made the choice to use CoffeeScript. If anything, this suggests that CoffeeScript has been a crucial part of the evolution of the JavaScript ecosystem, and there’s no reason to think that has changed because…
CoffeeScript Is (Still) Under Active Development
The frequency of commits to the CoffeeScript project is comparable to those for Node or io.js. Furthermore, they haven’t declined significantly over the past year. If anything, they’ve actually increased. In fact, a major new version of CoffeeScript was released just a few days before this post. If something is going to discourage continued work on CoffeeScript, it clearly isn’t going to be ES6.
Keep Using CoffeeScript (Yes, Even On New Projects)
So…CoffeeScript’s a language. Lots of developers use it. They’re still using it. It’s still getting better. It still has advantages over coding in JavaScript, even in ES6. We’ll still continue to use it whenever possible, until something truly better comes along. That isn’t ES6 (although I love the features ES6 brings to CoffeeScript). It probably isn’t ES7. It’s probably an entirely new language that leapfrogs CoffeeScript, possibly leveraging some of the capabilities in ES6/7 via a clever set of language idioms. But, until that language comes along, CoffeeScript is a great choice.
If you’re already using CoffeeScript, why switch to the language that’s imitating it?
And if you’re not, you can still dispense with piles of punctuation, the function
and this
keywords, and explicit checks for null using the ===
operator. All while binge-coding in a functional style with a real, actual programming language! What’s not to love?