

Tell HN: Meet CoffeeScript - grandalf
http://jashkenas.github.com/coffee-script/#overview

======
jashkenas
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...](http://github.com/jashkenas/coffee-
script/blob/master/src/grammar.coffee)

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>

~~~
grandalf
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.

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

~~~
jashkenas
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...](http://github.com/jashkenas/coffee-
script/commit/7667e16732268944232d31cea6a201698ce0661a#diff-5)

Thanks for that.

------
hackoder
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?

~~~
jashkenas
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.

~~~
10ren
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.

~~~
jashkenas
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.

------
jashkenas
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>

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

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

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

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

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

~~~
Tichy
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?

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

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

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

------
qeorge
I love the syntax for lambdas and existence checking.

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

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

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

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

~~~
brehaut
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.

~~~
fnid2
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;
      }

~~~
chromatic
_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?

~~~
jashkenas
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.

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

~~~
jashkenas
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>

------
david927
In a word: cool.

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

