Tell HN: Meet CoffeeScript
jashkenas.github.com
jashkenas.github.com
This means that you can compile scripts in the browser, should you choose to, or within Node.js on the server, and greatly increases the speed of the interactive REPL. It's also a nice showcase for what's possible in CoffeeScript.
For example, take a peek at the Jison parser, using a little DSL function that makes for a nice style of grammar declaration:
http://github.com/jashkenas/coffee-script/blob/master/src/gr...
If you'd like to play with the CoffeeScript-in-CoffeeScript implementation, use bin/node_coffee when you check out the source. bin/coffee remains the Ruby implementation until the CoffeeScript side is up to feature parity.
Here's the original post, things have come a long way since then:
Now I can play with it without that overhead and always compile down when done with development for speed. Kudos!
ages = (function() {
__a = []; __b = years_old;
for (child in __b) {
age = __b[child];
if (__hasProp.call(__b, child)) {
__a.push(child + " is " + age);
}
}
return __a;
}).call(this);
to: ages = (function() {
__a = []; __b = years_old;
for (child in __b) if (__hasProp.call(__b, child)) {
age = __b[child];
__a.push(child + " is " + age);
}
return __a;
}).call(this);
It's fairly minor but saves a few assignments and generates slightly less noise.I've pushed a patch that implements your suggestion, and all the tests are passing:
http://github.com/jashkenas/coffee-script/commit/7667e167322...
Thanks for that.
For anyone who uses this in an app, my guess is that it makes debugging (in firebug etc) kinda annoying? I mean, even though it maps directly to JavaScript, the mental context switch between what you see in firebug and the code you've written would take getting used to?
* The compiled output is pretty-printed instead of minified.
* Comments are passed through in-place to JavaScript.
* All functions are named functions, so instead of a stacktrace full of "anonymous", you can situate yourself.
* There's a "no special functions" rule -- CoffeeScript translates directly into JS without a standard library, which means that theres a one-to-one correspondence between your source code and its JavaScript equivalent, so it's not too hard to untangle.
That said, the temporary variable that we need to generate for some features are a little ugly, and sometimes we need to generate extra safety checks because we don't know certain things at compile time (such as, for example if a range counts upwards or down). Any suggestions for how to make the compiled JS more easily readable would be warmly welcomed.
i.e. by minifying the JS where coffee:js lines are 1:m and adding blanks when m:1, instead of always pretty-printing.
It's a trade-off of js-readability for error-readability - a hard call, but very cool to be able to go directly to the line in question.
http://github.com/jashkenas/coffee-script/issues/issue/132
Now that there's the self-compiler that can be run without ever saving the compiled JavaScript as a file, this becomes far more important.
http://www.fabjs.org/ http://code.quirkey.com/sammy/ http://github.com/visionmedia/express/
and there's no real trick to using them:
require 'express'
require 'express/plugins'
configure ->
use MethodOverride
use ContentLength
set 'root', __dirname
get '/hello', ->
@contentType('html')
'<h1>Hello World </h1>'
get '/user/:id?', (id) ->
@render 'user.haml.html', {
locals: {
name: if id? then 'User '+id else 'You'
}
} bin/node_coffee src/*.coffee --output lib/coffee_script
Just be careful, if you break it you'll have to check out the 'lib' directory again to get a working compiler back.It's all a matter of taste, but I can't see this as being more tasteful than js.
Also it's comparing to crappy js.
For example
// Splats:
race = function race(winner) {
var runners;
runners = Array.prototype.slice.call(arguments, 1);
return print(winner, runners);
};
Could be rewritten race = function race(winner) {
return print(winner, Array.prototype.slice.call(arguments, 1));
}This CoffeeScript:
send_letter: (name, addresses...) ->
# more code...
Where the array of addresses can be referenced and used as many times as you like within the function body, would need to be translated as this JavaScript: var send_letter = function send_letter(name) {
var addresses = Array.prototype.slice.call(arguments, 1);
# more code...
};
Which is both a good bit more to type, as well as more work -- you need to figure out the index from which to slice. The only difference with the generated JS is that the variable declaration is on a separate line -- a feature that allows all assignments to be used as part of a larger expression. number: -42 if opposite_day
however, almost anyone, even non-programmers can understand this: if (opposite_day) {
number = -42;
}What I care about from a languages syntax is that it makes programs clear to someone familiar with the language.
Like i mention previously C family programmers often cannot make head or tail of a Lisp or ML family program, yet both those languages have excellent syntax where the choices made allow the programmer to express their intentions very clearly.
Contrast this with the popular view of Perl; One persons perl code can be impenetrable to another experienced perl programmer.
Syntax matters, but the familiarity with that syntax for outsides only matters from a purely political perspective. If you want to make a successful language, make it C flavored and baroque. If you want to make a truly great language, make the syntax that is best suited to what you are doing.
number = -42 if opposite_day
Or this, if you prefer your conditions first: if opposite_day then number = -42Isn't that the Python fallacy? (Take away the curly braces, anyhow.)
Programming is a lot more than syntax. How many non-programmers do you know who understand the semantics of mutable assignment without having it explained?
obj: {prop: val}
obj.prop: val
obj = {prop = val}
obj.prop = val
But the main reason is to avoid the equals sign as a symbol for assignment, because it has such a different meaning that you would expect in its use in math (unless immutable), where it implies the equivalence of the expressions on the left and right side for the entire duration of your proof.Using colons, like JSON does to great effect, looks more like tagging a value with a label, which is much closer to the meaning of what you're actually doing in JS.
obj:
prop: value
prop2: value2
edit: I've opened a ticket for this, here: