CoffeeScript – OR – How I learned to stick with JavaScript
February 1, 2013 in Programming, Uncategorized
I have been playing around with building node.js applications using the Cloud9 online IDE. With node.js, there is a lot of asynchronous programming and, quite often, you fling around anonymous functions as one of the primary constructs to respond to the asynchronous events in node.js and the various node.js packages available.
You end up writing code like this a lot:
someNodeJSOperation(var1, var2).success(function(err, res) {
someOtherOperation(res.someProperty).on("done", function(obj) {
console.log("i'm done!");
res.end("HELLO WORLDZ!");
});
});
Some of you may, instead, name these, as they currently are, anonymous functions and declare them like normal functions in the local scope, then pass the function names. Why? I dunno, perhaps for readability and a way to easily see the separate functions being used. It doesn’t seem make it THAT much easier to follow, at least to me. Also, personally, if a callback or event handler is going to be used in just one case, I want to scope it anonymously. Anyways, however you do it, I do it like the example above.
As I write anonymous function after anonymous function, I get tired of always typing:
function(yadda, blah) { /* some code here */; return yadda.someMethod(blah); }
You see, I am, traditionally, a C# developer. Recently, I love working in the JavaScript world and, even more recently, digging node.js; however, I miss lambda expressions! In the C# world, I haven’t typed the actual word delegate in at least four years. When I need an anonymous function, I simply type something like:
(yadda, blah) => yadda.someMethod(blah); // does roughly the same as the above JavaScript example, but in a type safe C# way
I want something like this in JavaScript for my node.js applications, but node.js uses the V8 engine (good thing, it’s fast) and the V8 engine is ECMAScript compliant – not compliant to Mozilla’s JavaScript. While Mozilla has given JavaScript some great new features (like their version of lambda expressions in 1.8), none of these are available in ECMAScript.
I know there are a lot of languages that compile into JavaScript, one of them is CoffeeScript. There is also a node.js module for CoffeeScript (npm install coffee-script) that allows you to run CoffeeScript right in a node.js application without pre-compilation. Also, CoffeeScript’s default function syntax is pretty much a lambda expression:
(yadda, blah) -> yadda.someMethod(blah)
In fact, all functions in CoffeeScript are constructed this way. COOL! So I decided to port part of my Express application, a simple MVC example that is a basic REST-ful API for dealing with a MongoDB database and some more traditional HTML based views. This MVC application has a custom written wrapper for Express that mimics the default routing behavior of an ASP.NET MVC3/4 application.
My first task was rewriting my wrapper core. My wrapper automatically routes “/:controller/:action/:id” to default handlers that finds an appropriate <controller>.js file in the /controllers/ folder of my application (which are just node modules with all the actions as exports), then automatically calls the correct <action> method. If <id> is present, that is passed into the req.params as req.params.id (as Express already does). I have special response methods to redirect to another action in the controller and to render a view by looking in the /views/ folder of my application and finding the <action>.html file or a named view.
While I got the job done and my code looked “neat”, I wasn’t as happy with it as my original JavaScript code. Yeah, I like the function syntax and a few other features; however, CoffeeScript has so freaking much unnecessary syntactic sugar. I am OK with a little bit of that sugar (see my C# syntactic sugar series), but some seemed way more verbose and obtuse than the equivalent JavaScript’s syntax. The multitude of ways to construct objects and arrays were just asking for inconsistent messiness. Plus, ultimately, I like a good mixture of compact, performant, but still readable JavaScript. CoffeeScript looks compact, is somewhat readable, but I am not so sure of the performance benefits. The JavaScript output of some of my CoffeeScript, while relatively safe, is significant longer, and, honestly, I do not know of the performance impacts, to be honest.
Lets take a look of a couple of CoffeeScript functions I wrote and their JavaScript equivalent:
argRules = (args, rules...) ->
rules.sort((i1, i2) -> i1.length - i2.length)
len = args.length
for rule, i in rules
if len <= rule.length || i == rules.length - 1 then return rule.func(args)
view = (args...) ->
viewName = (if args.length == 0 then @action else (if args[0] instanceof String then args[0] else @action))
model = (if args.length == 1 && args[0] not instanceof String then args[0] else (if args.length > 1 then args[1] else null))
fullPath = "#{@controller}/#{viewName}"
@render(fullPath, model)
Not too bad, right? Here is the equivalent JavaScript it produces:
var argRules, view,
__slice = [].slice;
argRules = function() {
var args, i, len, rule, rules, _i, _len;
args = arguments[0], rules = 2 <= arguments.length ? __slice.call(arguments, 1) : [];
rules.sort(function(i1, i2) {
return i1.length - i2.length;
});
len = args.length;
for (i = _i = 0, _len = rules.length; _i < _len; i = ++_i) {
rule = rules[i];
if (len <= rule.length || i === rules.length - 1) {
return rule.func(args);
}
}
};
view = function() {
var args, fullPath, model, viewName;
args = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
viewName = (args.length === 0 ? this.action : (args[0] instanceof String ? args[0] : this.action));
model = (args.length === 1 && !(args[0] instanceof String) ? args[0] : (args.length > 1 ? args[1] : null));
fullPath = "" + this.controller + "/" + viewName;
return this.render(fullPath, model);
};
Ick! While, the original that I wrote in JavaScript is somewhat similar to this, the practices that the CoffeeScript compiler employs seem a little verbose to me. I var all my scoped variables, but usually declare and assign in one go. I probably wouldn’t have used arguments to manipulate my argument list if I knew I had to write all that; I would have passed in an array, instead, which is what I originally did, but changed it in my CoffeeScript to take advantage of its “features”. The for loop in the second method has some safety features on length testing, which is nice, but I don’t really need. Also, using if-then-else instead of the : ? operator – why?? Don’t even get me started on variable declaration and scoping (insert sad face).
There are some nice features. There is an easy way to keep this in a sub-function’s scope. Some of the array shortcuts are useful. Object and array comprehensions and destructuring seems useful. Even with their usefulness, is it creating extra script code that I don’t need under the hood? I dunno.
The price for the convenience, I guess, is less control of the underlying code. I just would have written it differently.
I just want freakin’ lambda expressions in my freakin’ JavaScript, is so freakin’ hard to ask for?
… hmm, TypeScript, interesting…







