The T-Files


Thu, 11 Aug 2011

CoffeeScript

CoffeeScript is a nice little programming language that compiles into Javascript. It exists to make life easier for Javascript programmers, and it achieves this by removing a lot of clutter and adding some nice syntactic sugar. At the same time, it stays close enough to Javascript to avoid the "impedance mismatch" other systems like GWT often suffer from: It does not change how anything works, there is no need for a special runtime library, you can call into (and be called from) any "regular" Javascript code, and the resulting Javascript is still readable and corresponds very closely to the CoffeeScript it was compiled from (which is good when you need to debug it). In fact, you are supposed to understand the transformations it does, and why. The Principle of Least Surprises is in effect, and the programmer stays in control.

Less clutter: CoffeeScript does away with most of Javascript's braces, parentheses, and semicolons. Especially when defining functions (which you will do a lot for example when working with callback-driven frameworks like node.js) and object literals, this really reduces the amount you have to type a lot. At the same time, this also reduces the amount you have to read, so once you get used to it, it should be easier to understand as well. The one thing that I am a bit uncomfortable here is that whitespace (in the form of indentation and line breaks) becomes significant, just like it does in Python. I found that it does actually align nicely with how I want to layout my code anyway, but I am a little worried about some hard-to-understand errors this might cause.

Syntactic sugar: CoffeeScript claims to have taken inspiration for these constructs from Python and Ruby, but I'd like to point out that those in turn have inherited them from Perl. In any case, it is very nice to have multi-line strings, string interpolation, array slicing, trailing if statements, and keywords like not or unless. There are also constructs to work with Javascript's prototype-based object system, with the frequent issue of context changes (this not being what you want it do be), and for looping over lists:

shortNames = (name for name in list when name.length < 5)

alert message for message in ['foo', 'bar', 'baz']
Fri, 17 Sep 2010

Fun with the Closure Compiler

The Google Closure Compiler is a tool for making JavaScript download and run faster by compiling JavaScript to equivalent, but more compact (and much less readable) JavaScript. If you crank it up to the max (ADVANCED_OPTIMIZATIONS), it does a couple of very aggressive optimizations.

Shorter variable names

var longName = "1234";
longName += 1;

// becomes (redundant whitespace is also removed)
var a="1234";a+=1;

Dead code removal

var neverUsed;
function neverCalled(x){return x++; }
alert(1234);

// becomes 
alert(1234);

Ahead-of-time evaluation of constant expressions ...

var x = 10;
var y = 20;
alert(x+y);

// becomes 
alert(30);

... even when it gets tricky

function inc(x){ return x+1; }
var x = 10;
var y = inc(inc(inc(x)));
if (y > 5){
   alert(y + ("a string"+x).length);
}
else{
  alert("impossible");
}

// becomes 
alert(23);

Function inlining

function inc(x){ return x+1; }
function plus3(x){ return inc(inc(inc(x))); }
function plus3squared(x) { return plus3(x) * plus3(x); }
// need to export the function otherwise it will be considered dead code
window["plus3squared"] = plus3squared;

// becomes
window.plus3squared=function(a){return(a+1+1+1)*(a+1+1+1)};

Pitfalls when using "newer" language features
Closure compiler only knowns about Javascript 1.5. If you use newer language features, you should probably not use the advanced optimizations. For example String.trim was added in JavaScript 1.8.1, and the compiler will happily clobber it:

alert("x".trim());

// unfortunately becomes
alert("x".a());
And there is no compiler warning or error message, so that you only find out about it when your program fails with a rather indecipherable error message at run-time. Debugging the compiled code is very hard (I hear there is a Firebug plugin to help, but have not tried it), so you usually want to develop using the uncompiled version. In this case, however, the bug is introduced by the compiler, and does not happen in the development Javascript (or when compiling at lower optimization levels).

Exporting symbols
Because all your code gets renamed, you cannot call it from external code (such as an onclick in the HTML) anymore. To solve this issue, you have to explicitly export your publicly accessible symbols.

function myClickHandler() {};
window["myClickHandler"] = myClickHandler;