Created
September 20, 2016 15:52
-
-
Save AsaAyers/d09e4de118b8d6b5e2d8fa3e38e496e0 to your computer and use it in GitHub Desktop.
Revisions
-
AsaAyers created this gist
Sep 20, 2016 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,156 @@ # You Don't Need CoffeeScript It's time to replace CoffeeScript with [Babel](http://babeljs.io/) and CoffeeLint with [eslint](http://eslint.org/). CoffeeScript was useful a few years ago. It provided many features that JavaScript was lacking. It gave us the fat arrow (lexical `this` functions), default parameters, destructuring assignments, splats (spread operator), a `class` keyword, block strings, and more. Everything in the list above is now part of the JavaScript standard. JavaScript is moving forward and gaining 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][transpilers] 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](https://github.com/AsaAyers/coffeescope), 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](https://github.com/michaelficarra/CoffeeScriptRedux/commits/master). That project appears to be dead. While CoffeeScript gained the ability to produce generators, they [can't implement syntax to use them](https://github.com/jashkenas/coffeescript/issues/3832) because `for...of` 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 these is the JavaScript it produces 1. `foo(bar) && hello(world)` 2. `foo(bar && hello(world))`` I got that example from [Goodbye CoffeeScript, Hello TypeScript](http://blog.heapanalytics.com/goodbye-coffeescript-hello-typescript/) ## Significant Whitespace The compiler is so loose that it only cares that blocks are indented different from the parent. ```CoffeeScript if zeroSpaces if oneSpace if threeSpaces if sevenSpaces undefined # 11 spaces ``` When you chain calls together CoffeeScript silently consumes whitespace. ```CoffeeScript $('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. ```CoffeeScript 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 `return undefined` ## Literate CoffeeScript 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. ## Comprehensions These seem nice, but are easily reproducible with [Array.prototype.map][map] and [Array.prototype.filter][filter]. ## Array Slicing and Splicing with Ranges These are nice. ## Operator Aliases You get to write `and` instead of `&&`! I'm not really impressed. This is kind of nice sometimes, but it's not significant. ## Existential Operator I want this in JavaScript. ## Chained Comparisons `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` ## Block Regular Expressions See https://www.npmjs.com/package/xregexp [map]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map [filter]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter [transpilers]: https://youtu.be/DspYurD75Ns?t=11m56s