Skip to content

Instantly share code, notes, and snippets.

@dfkaye
Last active March 10, 2022 05:49
Show Gist options
  • Save dfkaye/6842188 to your computer and use it in GitHub Desktop.
Save dfkaye/6842188 to your computer and use it in GitHub Desktop.
CoffeeScript fans - stop calling the skeptics "haters" - you undo any goodwill your enthusiasm should generate.

[first cut: 5 October, 2013].

CoffeeScript enthusiasts want to be productive - amen to that - but calling the skeptics names undoes any goodwill your enthusiasm should generate.

I think CoffeeScript is fine for driving tests, but in a high-performance application – which is "equivalent to the concatenation of its source files", Justin Searls, http://blog.testdouble.com/posts/2013-06-16-unrequired-love.html – you need to watch for bloat, and CoffeeScript (along with the CSS preprocessors) re-introduces that in subtle ways that should be acknowledged.

Debugging and tracing generated JavaScript in the browser requires source maps, so you can use Chrome DevTools, e.g. Relying on those tools is a small part of the cycle, with some potentially exciting gains (live reload in the browser, holy mackerel), but it introduces a hard dependency in the tool chain, rather than being tool-agnostic.

The Class implementation in the CoffeeScript interpreter is less than optimal. The boilerplate is repeated in every transpiled class file, e.g., and takes up more memory because it generates a closure it never releases - and closures take up performance with respect to symbol look-ups in the prototype chain. (If you don't understand that last part, please consult Nicholas Zakas' High Performance JavaScript, Chapter 1.)

[16 Oct 2013] Corrections to the class implementation argument

  • The boilerplate is created once per transpiled file - so if you're concatenating a lot of files prior to transpiling, the bloat doesn't happen.
  • And, no, there is no closure created by the __extends method.
  • BUT ~ CoffeeScript does enable static inheritance, where a child class inherits references to static properties on the parent.

Regardless whether CoffeeScript and JavaScript are semantically identical, syntactically they are not. The do keyword behaves very differently in each, for example. The function keyword required in JavaScript is verboten in CoffeeScript, being replaced by the arrow token ->. The significant white-space removes curly braces for blocks, semi-colons, and so on, meaning fewer keystrokes in total, but introduces required keystrokes for the interpreter.

Of course it's just a habit you can adjust to, but not all token elimination is equally helpful. Parentheses are often necessary for readability, as when passing an anonymous function as a parameter to another function, for example. Of the following which is easier to read?

vm.shim ->
    expect(value).toBe('found') 
  , { expect: expect, value: 'found' }
vm.shim (->
    expect(value).toBe('found') 
  ), { expect: expect, value: 'found' }

Both of these transpile to the following JavaScript.

vm.shim(function() {
  return expect(value).toBe('found');
}, {
  expect: expect,
  value: 'found'
});

A comment in either would certainly help here - but there again, comments in JavaScript (// and /* */) are not supported in CoffeeScript, which requires the # character instead.

The cognitive load introduced by each of these differences may be slight, but it is real and it adds up. When people are complaining about that, be mindful as you would to a user complaint about your app costing time by using non-obvious conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment