In the past 6 months I've become submersed in Coffeescript. I've used it for building both Angular applications and smaller JavaScript functionality in the context of a couple larger Rails applications. Prior to that I spent about a year building a really large angular application and a wide variety of smaller projects in JavaScript.

Having done quite a bit with JavaScript, I admittedly wasn't psyched to start doing CoffeeScript. Now, after using it for a while, I don't find it quite as annoying and I might even admit its useful (maybe even nice) for small, add-on type things inside frameworks like Rails. That said, I'm more convinced everyday that CoffeeScript has several, serious shortcomings which make it a poor choice for large-scale applications.

Feature Failures

CoffeeScript provides a few nice features like splat syntax and list comprehension but several features and choices make it far more confusing than JavaScript. In addition to these complaints, its important to remember that CoffeeScript is a subset of JavaScript - it can't do everything which JS can and you can't just paste JavaScript into your CoffeeScript.

  • Inconsistent, forced type safe equality
    Coffeescript forces ALL explicit equality to be type safe, all == are transformed into === when transpiled to JavaScript. However, implicit equality, e.g. if test then something() is evaluating the truthyness of test - test == true.
    This inconsistency in evaluation of truthyness makes the already weird type coercion in javascript even more confusing in CoffeeScript.
    It is also, in my opinion, silly to force a developer 'know' the type of a value in JavaScript transpiler - this just isn't how JavaScript works. The loose typing is particularly important/useful in the context of evaluating html attributes and json decoded values.
  • Automatic return from functions
    Sometimes automatically returning the last value from a function is a nice shortcut. However in javascript, where many times we're writing event handlers and callback functions, forcing a return value is often annoying and can sometimes cause hard-to-spot errors. For example - accidentally returning false from an event can have unintended consequences. In angular, functions which are called from a expression are not allowed to return a DOM element. Its very easy, if you're manipulating an element in some way (affixing it, animating it, etc.. I know, I know), to accidentally return an element and cause your app to crash. This feature overall seems unnecessary and annoying. I often find myself just returning null explicitly to prevent my own confusion.
  • All functions are anonymous
    Its not possible to declare a named function, which prevents certain possible weirdness with hoisting, but makes it difficult to test and profile the code you write.
  • Somehow-Even-More-Confusing Scoping
    Because scoping is not declarative in Coffeescript, its very easy to make major errors and not see them. To understand, have a look at this example.
    The console.log at the end prints [2, 4, 6, ..., 24] when run. This weird problem is totally non-obvious from looking at the CoffeeScript. Essentially, you can't shadow a variable in a sub scope in CoffeeScript... which can lead to really difficult-to-debug problems.

Syntax Annoyances

There are a variety of small, opinion based things that annoy me about CoffeeScript. Since I'm writing a blog post about it, I might as well list them out.

  • Significant Whitespace
    This is a debatable one, I know - I personally don't like significant whitespace. I'll leave it at that.
  • Functions as Parameters are Difficult to Read
    When passing functions as parameters to other functions, the lack of deliminators makes things really confusing - for example:

          $http.get('/info').then (response)->
              doSomething(response);
              if response.thisThing
                  somethingElse()
              else
                  showWeirdResponseMessage()
          , (err)->
              showErrorMessage()
    

    I personally find this very difficult to read and understand and its very easy to make mistakes. Wrapping each function in parenthesis can make things slightly better, but not having a nice way to pass functions as parameters in a callback driven, asynchronous world is a major oversight.

  • Longer Ternary Syntax
    This is a really minor one, but I just think its silly that a syntax that is all about shortening the syntax removed the ternary operator. Instead we're forced to do if something then 1 else 2.

Conclusions

On top of these issues, CoffeeScript is a transpiled language, which means it gets changed into JavaScript before running. This means there is an additional step between writing code and it being run in the browser. it also means the code will be debugged and profiled as JavaScript, meaning that developers MUST know JavaScript to produce good CoffeeScript.

With all these things combined, I find CoffeeScript detracts from my coding more than it adds. While much of the JavaScript world hops onto the declarative bandwagon with AngularJS and other similar frameworks, CoffeeScript does its best to use convention over declaration. Overall, I find that I'm slower and more error prone than when writing JavaScript.

Finally, this quote from the creator, Jeremy Ashkenas, says the rest:

I can't justify using it for the main DocumentCloud development. Imagine trying to hire someone. "You'll have to learn to use a new language that we made up..."
- ReadWriteWeb

In my opinion, we should be moving away from CoffeeScript and focusing on writing good JavaScript and using/developing frameworks and libraries to make our lives and jobs easier and more fun. Try out underscore.js and Angular, write helpers when it takes a lot of code to do what you want, add macros and shortcuts for annoying syntax ... but learn JavaScript in and out - its good and bad - this will be much more valuable in the long term.