You Don't Need CoffeeScript
CoffeeScript was useful a few years ago. It provided many features that
default parameters, destructuring assignments, splats (spread operator), a
class keyword, block strings, and more. Everything in the list above is now
adoption and better tools where CoffeeScript isn't.
But why isn't CoffeeScript getting better tools? Let's take a look at what Jeremy Ashkenas had to say in CODE GENIUS - Rise of the Transpiler at 11:56.
We like to cheat and make things easier for ourselves ... this is not kosher, it is introducing context sensitivity into the lexer process. If you took the actual class you would get an F doing this kind of thing. But it's just programming, it's just code. You can cheat if you want to cheat
In the end that kind of cheat meant that I can't build a tool that tracks variables, so I can't reliably build lint rules around unused or undefined variables. Typical compilers produce an Abstract Syntax Tree, or AST. The AST is a data structure that has all the info needed to produce target code. But, CoffeeScript's "AST" isn't a data structure to be read, instead it's a mix of data and executable code that modifies its own structure as it runs to fill in things like implicit returns.
Surely CoffeeScript Redux will save us! The description at the top of the project is "rewrite of the CoffeeScript compiler with proper compiler design principles and a focus on robustness and extensibility". The last change in that project that actually touched code was over a year ago. That project appears to be dead.
While CoffeeScript gained the ability to produce generators, they can't
implement syntax to use
already has an incompatible meaning in CoffeeScript.
Surely there must be some benefits of using CoffeeScript today. If you look through coffeesript.org's home page, these are the features, or sometimes mis-features that CoffeeScript provides.
Optional function parenthesis
pop quiz! Given this line of CoffeeScript
foo bar and hello world which of
foo(bar) && hello(world)
- `foo(bar && hello(world))``
I got that example from Goodbye CoffeeScript, Hello TypeScript
The compiler is so loose that it only cares that blocks are indented different from the parent.
if zeroSpaces if oneSpace if threeSpaces if sevenSpaces undefined # 11 spaces
When you chain calls together CoffeeScript silently consumes whitespace.
$('body') .addClass('k') .removeClass 'k' .animate() .hide()
You might think those calls are indented, but technically they aren't. CoffeeScript simply consumes that indentation forcing CoffeeLint to need special hacks to lint that code.
Lexical Scoping and Variable Safety
"Safety" is a hilarious claim. Your variables are actually far less safe
because they are implicitly declared. how many times have you had a
path = require('path') in your code, and then somewhere you have a loop that operates
on a file path, so you called the variable
path? I'd have a rule catch this
for you, but as explained above, you can't build one properly out of the AST.
There is a 3rd party rule that attempts this, but it's incomplete.
scope1 = -> # bar is created here in scope 1 thanks to variable hoisting scope2 = -> # foo is created here in scope 2 foo = "foo" scope3 = -> console.log(bar) bar = foo # outermost foo reference. Doesn't create the variable # outermost bar assignment does create the variable
Everything is an Expression (implicit returns)
Everything being an expression did seem nice when I used it. Implicit returns
for any multi-line function is just a bad idea though. You can never really tell
if a function needs to return something or not, because it will either way. I
have had times where I had to go track down all the callers of a function to
figure out if any of them were using the return value or the return value was
accidental because I didn't opt out of it with an explicit
It's an interesting idea, but I never found it useful. I tried to use it a few times, but it didn't really make sense in any project I ever worked on.
Array Slicing and Splicing with Ranges
These are nice.
You get to write
and instead of
&&! I'm not really impressed. This is kind
of nice sometimes, but it's not significant.
healthy = 200 > cholesterol > 60
This would be nice, but since we don't have it you just repeat the inner variable.
const healthy = 200 > cholesterol && cholesterol > 60