Post on 15-Jan-2015
description
5 things I learned about coffeescript
(in my year with it)
Wednesday, June 5, 13
Dean Hudson, @deaneroSenior Engineer, Super Secret Music Start Up
(and hiring!)
Who Am I?
Wednesday, June 5, 13
1. coffee -cp
Wednesday, June 5, 13
dean@hdh:~/Devel/coffee$ coffee --help
Usage: coffee [options] path/to/script.coffee -- [args]
[...] -c, --compile compile to JavaScript and save as .js files -p, --print print out the compiled JavaScript [...]
Wednesday, June 5, 13
to see that this...
Wednesday, June 5, 13
qsort = (ar) -> return ar unless ar.length > 1 pivot = ar.pop() less = [] more = [] for val in ar if val < pivot less.push(val) else more.push(val) qsort(less).concat([pivot], qsort(more))
module.exports = qsort
Wednesday, June 5, 13
...compiles to this:
Wednesday, June 5, 13
dean@hdh:~/Devel/coffee$ coffee -cp qsort.coffee // Generated by CoffeeScript 1.4.0(function() { var qsort;
qsort = function(ar) { var less, more, pivot, val, _i, _len; if (!(ar.length > 1)) { return ar; } pivot = ar.pop(); less = []; more = []; for (_i = 0, _len = ar.length; _i < _len; _i++) { val = ar[_i]; if (val < pivot) { less.push(val); } else { more.push(val); } } return qsort(less).concat([pivot], qsort(more)); };
module.exports = qsort;
}).call(this);dean@hdh:~/Devel/coffee$
Wednesday, June 5, 13
2. Program with class
Wednesday, June 5, 13
Wednesday, June 5, 13
(me, 16 months ago)
Wednesday, June 5, 13
There’s only one way to do it.
It reduces mental overhead for devs.
It just works.
Because! With class...
Wednesday, June 5, 13
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child;};
Wednesday, June 5, 13
__extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor(); child.__super__ = parent.prototype; return child;};
Tricksy! And...
Wednesday, June 5, 13
// Generated by CoffeeScript 1.4.0(function() { var Greet, Hello, __hasProp = {}.hasOwnProperty;
Greet = (function() {
function Greet() {}
Greet.prototype.greet = function() { return 'hi'; };
return Greet;
})();
Hello = (function(_super) {
__extends(Hello, _super);
function Hello() { return Hello.__super__.constructor.apply(this, arguments); }
Hello.prototype.hello = function() { return 'hello'; };
return Hello;
})(Greet);
}).call(this);
Wednesday, June 5, 13
// Generated by CoffeeScript 1.4.0(function() { var Greet, Hello, __hasProp = {}.hasOwnProperty;
Greet = (function() {
function Greet() {}
Greet.prototype.greet = function() { return 'hi'; };
return Greet;
})();
Hello = (function(_super) {
__extends(Hello, _super);
function Hello() { return Hello.__super__.constructor.apply(this, arguments); }
Hello.prototype.hello = function() { return 'hello'; };
return Hello;
})(Greet);
}).call(this); ...verbose
Wednesday, June 5, 13
vs.
Wednesday, June 5, 13
class Greet greet: -> 'hi'
class Hello extends Greet hello: -> 'hello'
Wednesday, June 5, 13
3. Use comprehension
idioms!!!!!
Wednesday, June 5, 13
# what's wrong with this code?_ = require 'underscore'
ar = [1,2,3,4,5,6,7,8,9]
doubled = _.map(ar, (x) -> x * 2)
Wednesday, June 5, 13
doubled = i * 2 for i in ar
YOU DON’T NEEDA LIBRARY!!!
Wednesday, June 5, 13
// Generated by CoffeeScript 1.4.0(function() { var ar, i, map, _i, _len;
ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (_i = 0, _len = ar.length; _i < _len; _i++) { i = ar[_i]; map = i * 2; }
}).call(this);
Wednesday, June 5, 13
// Generated by CoffeeScript 1.4.0(function() { var ar, i, map, _i, _len;
ar = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
for (_i = 0, _len = ar.length; _i < _len; _i++) { i = ar[_i]; map = i * 2; }
}).call(this);
This is also faster.
Wednesday, June 5, 13
ar = [1,2,3,4,5,6,7,8,9,10]
aSelect = i for i in ar when (i % 2) == 0aMap = i * 2 for i in araFind = (i for i in ar when i == 0)[0]
Similarly...
Wednesday, June 5, 13
4. One class per file
Wednesday, June 5, 13
Node.js provides a synchronous require
Stitch and browserify use node semantics
Require.js does AMD
How? A library.
Wednesday, June 5, 13
5. Watch your return values.
Wednesday, June 5, 13
dontRunInATightLoop = (object) -> # I meant to mutate this object and return void... object[k] = "#{v}-derp" for k, v of object
This...
Wednesday, June 5, 13
dontRunInATightLoop = function(object) { var k, v, _results; _results = []; for (k in object) { v = object[k]; _results.push(object[k] = "" + v + "-derp"); } return _results;};
...compiles to this.
Wednesday, June 5, 13
Comprehensions+
Implicit returns
Wednesday, June 5, 13
=many allocations
Wednesday, June 5, 13
okayToRunInATightLoop = (object) -> object[k] = "#{v}-derp" for k, v of object # I need to do it explicitly return
Wednesday, June 5, 13
Questions?
Wednesday, June 5, 13
Thanks!@deanero
http://ranch.ero.com(I’m hiring Rubyists!)
Wednesday, June 5, 13