Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Tell HN: Meet CoffeeScript (jashkenas.github.com)
87 points by grandalf on Feb 14, 2010 | hide | past | favorite | 40 comments


Oops. I was hoping to post this to HN in a couple of days when it's finished, but the latest commits to CoffeeScript on Github include a compiler that's written entirely in CoffeeScript. It's been compiling itself since Friday.

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:

http://news.ycombinator.com/item?id=1014080


Sorry about posting it early :) I must have missed the original story and when I discovered it today I thought it merited sharing with HN.


Brilliant. I was turned off by the need to compile separately with Ruby.

Now I can play with it without that overhead and always compile down when done with development for speed. Kudos!


Is there any reason the object comprehensions can't be rewritten from:

    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.


Thanks, grayrest. That's a nice improvement that has the lovely side effect of simplifying the code generation needed to implement comprehensions.

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.


Beautiful to look at.

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?


We're trying to be pretty careful about keeping the compiled JS debuggable. To that end:

* 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.


My dream would be to be able to decompile JS into CoffeeScript, so I could make changes in either form. That would probably be difficult to do for some of the more advanced features, though.


To make the line numbers in JS error messages more informative, you could make the line numbers coincide.

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.


Ah yes, we have a ticket for this.

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.


Alright, just pushed a quick update to the documentation page that includes the self-compiler. You can try compiling CoffeeScript expressions in the browser right here:

http://jashkenas.github.com/coffee-script/#try_coffee


Excellent work Jashkenas! I think what would really let you achieve liftoff (and a book deal with a tech publisher) would be a Sinatra-like framework based on this. The Sinatra core is very small and has wowed a lot of people, replicating it so that people are using coffeescript serverside and also in the client would be amazing. I imagine a 300 page book equally divided between the language, server-side and client-side would sell really well with a 1.0 release. I can easily picture a rails-like ecosystem (with associated business and publishing opportunities) surrounding this in the future.


There's no real shortage of sinatra clones for js:

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'
            }
        }


So far, one of my favorite features of CoffeeScript is how responsive you are to questions comments and concerns jashkenas.


Is there a chance to add macros? Don't know enough about macros to know if it was doable for CoffeeScript, but only today I run into a situation where I thought it would be nice to have them in JS.


Mind explaining the situation that you encountered? Maybe we can come up with something.


I am afraid it already slipped my mind as it was several hours ago. But I am sure another situation will arise. Where would be a good place to discuss it, as this thread will long have been gone stale by then?


Repost, but great job. I really like how crud-free it is compared to the javascript versions of the same scripts.


If anyone wants to try tweaking the grammar and recompiling the language, you can run this:

    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.


Ah, the existential accessor operator is lovely. It really warms the heart to see variations on the Maybe monad sneaking into other languages--if there's one thing from Haskell I miss elsewhere, it's that.


I love the syntax for lambdas and existence checking.


The script syntax is less intuitive than javascript and doesn't save that many lines, so I'm not sure it's something I'd ever use.


Not 'less intuitive', it is 'less familiar'. These sorts of comments are largely subjective. See also C family programmers looking at Lisp or ML family languages.


You are going to have a very hard time convincing me that anyone who doesn't know Coffeescript syntax is going to undertand what this means:

   number: -42 if opposite_day
however, almost anyone, even non-programmers can understand this:

  if (opposite_day) {
    number = -42;
  }


Personally i don't care what someone who doesn't understand language X can make of a piece of code written in language X.

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.


You can also do this, if you prefer equals signs:

    number = -42 if opposite_day
Or this, if you prefer your conditions first:

    if opposite_day then number = -42


That may be true, but what about when opposite_day is null vs undefined ... there are a lot more improvements than just inline conditionals.


Admittedly, I wrote something in Perl three years ago, but that line is perfectly intuitive to me.


makes sense when you use ruby the bulk of your day :)


even non-programmers can understand this

Isn'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?


I'm glad you brought up mutable assignment. The reason for allowing colons as an alternative to equals signs in CoffeeScript is two-fold, the lesser reason is to make regular assignment consistent with JSON assignment, eg, both of these are legal CoffeeScript:

    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.


So it's almost identical, but with worse (IMHO) syntax!

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));
  }


There's no question that the generated JavaScript is never going to be as pretty as handwritten JS. But that said, choosing splats as your example of bad syntax isn't the best choice, because there isn't a syntactic equivalent in JavaScript.

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.


The JavaScript examples don't show what you would write in JavaScript, they show the compiled JavaScript output when you write it in CoffeScript.


You hate everything. Maybe you should just not read this type of article.


Yeah you're right. I'll try hard to ignore the "language syntax sucks/rocks/is so important" articles.


Why are braces needed in the Math declaration? Is this not Pythonlike enough to use the indentation, or is there something else?


The braces are there because JavaScript's object literals are already pretty nice. But it would certainly be an interesting feature, if assigning to a block implied an object literal.

    obj:
      prop: value
      prop2: value2
edit: I've opened a ticket for this, here:

http://github.com/jashkenas/coffee-script/issues/issue/146


In a word: cool.


Okay, enough of these metalanguages. These languages might make it slightly easier to write your program, but the inability to use standard development tools with it results in you loosing more time in the end.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: