

CoffeeScript -- You Are Totally Gonna Hate It - jashkenas
http://www.slideshare.net/tim.lossen.de/coffeescript-7-reasons-you-are-gonna-hate-it

======
waxman
Just wrote an API in CoffeeScript, using Node.js and Express.

It was surprisingly enjoyable. I can see this ecosystem giving
Rails/Sinatra/Django a real challenge. CoffeeScript makes ssjs a lot easier
once you get used to it, Node.js gives you free non-blocking/high concurrency,
and Express, which just released 1.0, is quickly maturing into a really solid
DSL/web framework.

I'm excited to see how this ssjs scene unfolds.

~~~
jashkenas
I'm excited to see how the judicious use of JavaScript will evolve webapps
beyond the Rails/Sinatra/Django paradigm, and allow you to share the code for
your application between the client and the server. V8/Node.js is just the
cherry on top:

[http://shootout.alioth.debian.org/u32/code-used-time-used-
sh...](http://shootout.alioth.debian.org/u32/code-used-time-used-shapes.php)

Thanks to the effort put in by the V8 team, JavaScript is now an order of
magnitude closer to C speed than Ruby, Python, and Perl, and sits at the same
tranche of performance as OCaml and Go.

~~~
FraaJad
The really interesting language in that comparison is LuaJIT. It is faster and
more concise than Javascript. It's sad that a mature, small, concise language
like Lua doesn't have more traction outside niches.

~~~
pygy_
Lua fails in the "batteries included" domain. It is first and foremost
developed as an extension language.

Furthermore, they are not really trying to promote the language beyond its
current niches.

That said, there are good third party libraries and frameworks, and a
Rubygems-like system called Lua Rocks.

~~~
krakensden
yeah, but so does Javascript

~~~
brehaut
But the one battery that is included in JS makes it unavoidable, and most
programmers (the kind that don't read HN or proggit) are the kind to not want
to learn another language. If you have the choice between using the quirky
thing you know or learning something else, its a good bet most programmers
will choose to use the tool the know, quality of the respective tools be
damned ;)

~~~
krakensden
"Batteries included" refers to a comprehensive standard library, which
Javascript doesn't have.

The fact that Javascript is an in important feature in software that everyone
runs is a whole different kind of advantage.

------
gmac
I've recently been using CoffeeScript in conjunction with the Ojay wrapper for
YUI (<http://ojay.othermedia.org>), which includes JS.Class ("Ruby-style
JavaScript", <http://jsclass.jcoglan.com/>).

I've found the combination absolutely brilliant -- it recalls Ruby's creator
Matz's promise of a language to "make programmers happy".

You get the expressiveness and brevity of Ruby, plus first-class functions,
running in anyone's browser; and you get really well-thought-out event
handling, AJAX and animation APIs.

I have only one serious pain-point with CoffeeScript: the Pythonesque
significant whitespace. This commonly trips me up when providing anonymous
function arguments to other functions (very common when assigning event
listeners, for instance).

I guess the problem is that I never really understand exactly which whitespace
is going to be deemed significant -- so maybe it's just a matter of
documentation?

~~~
jashkenas
If you can show me a couple examples of places where the indentation tripped
you up, I'd love to fix the documentation to explain them. Either starting a
ticket, or gist-ing the examples here would be fine.

There was a question in #coffeescript last night about passing multiple
anonymous functions into a function, and we came up with a couple of nice ways
to write it:

<http://gist.github.com/479249>

~~~
gmac
Thanks. Obviously I've fixed the original problems now, but if I get a chance
to try to recreate them I'll be in touch.

I should have mentioned that's the other thing to love about CoffeeScript:
insanely responsive support!

------
10ren
The "try coffeescript" demo (<http://jashkenas.github.com/coffee-script/>) is
really cool. It converts to javascript in realtime/as you type, including
error checking on the fly.

I like the lambda syntax (I don't recall seeing exactly this syntax before):

    
    
        () -> alert("lambda")
    
        (() -> alert("lambda")) ()     # to call it

~~~
jashkenas
CoffeeScript lets you leave off parentheses when they're not necessary to
describe what you mean. Your example can also be written as:

    
    
        -> alert 'lambda'
    
        (-> alert 'lambda')()  # to call it

~~~
d0m
It's a matter of opinion, but I don't particularly like when you can "omit"
things.. and sometime it works and sometime it doesn't. Yes, sometime it makes
the code a little clearer, but it can often lead to sneaky bugs and confusion.

I mean:

map x -> x _x seq

might be readable ..

but:

map x -> x_x seq seqs

is less clear.. while:

(map (x -> x*x) (seq seqs)) is more readable.

~~~
jashkenas
My two cents on optional parentheses, optional commas, and optional syntax in
general are that it's about readability and style. If the statement that
you're writing isn't clear without disambiguating the structure, then by all
means, use parentheses. But if you're choosing between this:

    
    
        print("Hello");
    

And this:

    
    
        print "Hello"
    

(Which are equivalent in CoffeeScript) ... I'll take the latter every time.

------
Elrac
I thoroughly hated that ignorant, nasty slide show displaying piece of crap
used to present the stuff. It kept wresting control away from me so I couldn't
view the slides at my own pace. What ever happened to text on a page, dammit?

~~~
pornel
Fake your UA to be iPad, and you'll get fast, clutter-free Slideshare.

~~~
mkramlich
if the OA would have just been plain text/images in HTML then everyone would
get fast clutter-free with any web client, any platform, with less code, less
complexity, etc.

------
endtime
I've been using CoffeeScript the last few weeks (writing a library using
Raphael) and I'm really enjoying it. My one complaint is that the
documentation has a few holes - in particular, it took me a little while to
work out how to do block comments (### on either end), and more importantly,
there's nowhere near enough documentation on cake. Right now my Cakefile uses
child_process.exec, which is kind of lame and also doesn't show compilation
errors.

~~~
jashkenas
Thanks for the documentation tips -- it's always helpful to hear what's
missing from the perspective of a pair of fresh eyes. I've updated the
documentation with an example of block comments:

<http://jashkenas.github.com/coffee-script/#heredocs>

And extended the section on "cake" a little bit with a better example that
demonstrates passing in a command-line option. It sounds like your problem is
different though -- here's the Node.js docs for child_process.exec:

<http://nodejs.org/api.html#child_process-exec-95>

You can use the "stderr" argument in the callback function to print the
child's error output to the console. Running this bit of CoffeeScript, for
example, will print out "to stderr":

    
    
        {exec}: require 'child_process'
    
        exec 'echo "to stderr" >&2', (err, stdout, stderr) ->
          print stderr

~~~
endtime
Thanks Jeremy. I don't particularly want to use child_process.exec if there's
a better/more direct way to compile, which it seems like there must be. I
think it would be really helpful to have a dead simple Cakefile example for
compiling a single CS file into a single JS file. It's not clear to me what
the standard way to do that is, even with your new example.

~~~
jashkenas
I'm sorry -- if you'd like to use the compiler directly, here's an example:

    
    
        fs: require 'fs'
    
        fs.readFile source, (err, code) ->
          try
            js: CoffeeScript.compile(code.toString(), {source})
            fs.writeFile 'out.js', js
          catch err
            console.log err
    

Here's the source of the "CoffeeScript.compile" method:

[http://jashkenas.github.com/coffee-
script/documentation/docs...](http://jashkenas.github.com/coffee-
script/documentation/docs/coffee-script.html#section-5)

~~~
endtime
Oh, cool, thanks. I also just learned that {source} is short for {source:
source}. That's something else missing from the docs, I believe.

------
exit
i really like coffeescript.

one part i'm ambivalent about though is assignment and conditionals. there are
too many ways to do the same thing, and i sit there wondering whether i'm
using the "right" one.

------
billpg
The slides didn't make a lot of sense (to me) without some sort of commentary.
I presume from the title I'm not supposed to be familiar with the language.

~~~
stwe
This was a talk given by Tim at the JavaScript User Group Meeting Berlin in
May 2010. There is also a video of the talk, but I can't find that anymore.

~~~
stwe
Found the video: <http://www.ustream.tv/recorded/7069443> The talk starts at
at 2:20 and ends at 10:00.

------
mathgladiator
Very interesting way to sell a programming language since haters gotta hate. I
should have tried it with the programming language I wrote.

------
bentlegen
I was expecting that one of the reasons would be "JavaScript is a perfectly
good language on its own."

~~~
TrevorBurnham
I wouldn't say that JavaScript is "perfectly good." For instance, the
statement "i=0" declares a global named i, unless there's a "var i" statement
in a closer scope. It's a very, very easy mistake to make, and can lead to
hours of debugging.

JavaScript is good, but CoffeeScript removes many of its imperfections, as
well as offering a far better syntax.

~~~
aaronblohowiak
jslint will help you to identify the global issue and takes seconds instead of
hours.

~~~
Scramblejams
Any time I have to reach for an external tool to figure out what's wrong with
my program, I wonder if the language/framework/library/whatever could be
improved to help prevent the problem in the first place. Valgrind much?

------
dreyfiz
I'm sold. Does it have a translator for all my old js, like sass-convert? And
can I set it to watch a directory for changes and recompile if I save a file,
like "compass watch"?

~~~
jashkenas
It doesn't have a translator from JS to Coffee, I'm afraid. There isn't a one-
to-one mapping (ie. detecting when you're actually using a for loop as an
array comprehension).

As for watching a directory for changes, absolutely. Just pass "--watch" to
the "coffee" executable. For example:

    
    
        coffee --compile --watch --output lib src/
        
        coffee -cw -o lib src/
    

Which will watch "src" for changes, and compile all ".coffee" files inside to
".js" files in "lib", preserving the directory structure.

~~~
dreyfiz
I've been working with coffeescript all evening and I'm loving it. My one
suggestion/complaint so far is that you should follow Python more closely in
refusing to accept an assignment in conditionals and insisting on comparisons
only, because it eliminates a lot of bugs. E.g. if I type

    
    
      if x = y
    

The compiler should raise a syntax error.

~~~
jashkenas
Glad you mentioned that point. The distinction between '=' and '==' in most
programming languages is a personal pet peeve of mine. I think that it
confuses two separate issues: labeling a value with a name, and testing the
equality of values. Terrifically confusing stuff if you're coming from
algebra.

So, although '=' is available to make transitioning from other languages
smoother, idiomatic CoffeeScript would use ':' for assignment, both within and
outside of object literals, and would use 'is' for equality. Harder to make a
bug out of:

    
    
        if x is y

~~~
dreyfiz
Thanks, I'd somehow missed "is" and "isnt" in the docs!

------
WilliamLP
This is what, attempt number seven hundred and fifty two to create a
mainstream language that encourages functional programming?

Incidentally, what's the most successful recent language that tries to make
functional programming terser by not having an explicit "return" keyword
(everything's an expression)? I'm genuinely curious, and don't think any
significantly great number of programmers will ever find this style easier.

~~~
endtime
CoffeeScript isn't an attempt to encourage functional programming so much as
an attempt to combine the nice features of JS with a more modern syntax.

~~~
WilliamLP
Is "square: (x) -> x*x" more modern syntax, or simply more functional? It
surely isn't a new idea, maybe as old as Lisp, and a number of other new
languages are explicitly imperative.

------
pdelgallego
It the compiled code compatible with the Strict mode in ECMAScript 5?

Did the language remove any of the "bad parts"?

~~~
jashkenas
In general, the compiled code should pass JavaScript lint without errors, and
_can_ be compatible with ECMA5 strict mode, but does not enforce it (because
strict mode has a lot to do with runtime implementation, which we can't do
anything about). Looking at page 233 of the spec:

[http://www.ecma-international.org/publications/files/ECMA-
ST...](http://www.ecma-international.org/publications/files/ECMA-
ST/ECMA-262.pdf)

Most of the strict mode restrictions have to do with "arguments" and "eval",
which CoffeeScript doesn't affect. The two bits that we do enforce are:
"Assignment to an undeclared identifier or otherwise unresolvable reference
does not create a property in the global object," and "Strict mode code may
not include a WithStatement" -- the former because variable scoping is
automatic, and the latter because there is no "with" statement in
CoffeeScript.

But there are a number of other, more important bad parts that are omitted,
beyond strict mode: JavaScript's string-based switch statement, coercive
equality checks, named function statements, trailing commas, and so on...

------
endergen
Is the heredoc syntax for documentation? Or is it syntactic sugar for
multiline text? Because that would be very nice.

~~~
jashkenas
It's syntactic sugar for multiline strings. It lets you write out formatted
blocks of text that preserve indentation, allow you to use double-quotes and
single-quotes inside without escaping, and because we have ECMA Harmony-style
string interpolation -- you can interpolate values into heredocs as well.

For example, here's a hypothetical message:

    
    
        email: """
               Dear $recipient,
    
               You should receive your $product
               in the mail in $product.eta days.
               
               Thanks,
               $sender
               """

~~~
endergen
That's really nice, I would love that both for the above use of multiline text
to be printed. But especially for client-side html templates.

I'm building my own javascript preprocessor language called O. I will
definitely have to use that one, I hadn't thought of adding that. Should have
considering it's in PHP, Pything, etc.

ps. I like the look of coffeescript, and the principle of having everything be
an expression. What other kinds of properties does it enforce? Are you going
to be adding any more features/property-preservations?

I'm trying to shoot for two interesting properties, 1) To be able to compile
it back down to C/C++ for server side speed increases(Say in projects like
Node.js where you can pretty easily hook in C/C++ modules. 2) To have the
property of all code be reversable, and branchable for some interesting use
cases. The reversability ties into some Networking/User-Interface Libs I'm
making.

I'm curious what kind of tricks you used for implementing Coffeescript. Did
you use hand made parsers, Parsing Expression Grammars, or base it on any
other good projects?

~~~
jashkenas
Compiling a single language into JavaScript source code as well as C or C++ is
going to be one hell of a trick. I think it'll be very difficult to keep the
semantics the same, without resorting to running the equivalent of a
JavaScript interpreter inside of your C++, but I wish you the best of luck
with it.

If you'd like to discuss the implementation, feel free to drop by
#coffeescript on freenode. But to give you the rough outline -- the compiler
is made up of (in order), a Lexer, Rewriter, Parser, and AST of Nodes. The
lexer creates the tokens, the rewriter rewrites the stream of tokens,
disambiguating parses and allowing for optional syntax, the parser generates
the AST of nodes, and then "compile()" is called on the root node, and walks
down the tree, compiling the JavaScript string recursively.

For the parser, I'm using the excellent Jison parser generator for JavaScript,
in LALR(1) mode. The only really unorthodox part of this is the Rewriter. It's
not kosher to munge a token stream before parsing it -- but it's removed a
_ton_ of complexity from the grammar to not ever have to handle the
syntactical edge cases, and to have them resolved in advance. All of the
source is annotated, so here's some links:

* Jison: <http://github.com/zaach/jison>

* Lexer: [http://jashkenas.github.com/coffee-script/documentation/docs...](http://jashkenas.github.com/coffee-script/documentation/docs/lexer.html)

* Rewriter: [http://jashkenas.github.com/coffee-script/documentation/docs...](http://jashkenas.github.com/coffee-script/documentation/docs/rewriter.html)

* Grammar: [http://jashkenas.github.com/coffee-script/documentation/docs...](http://jashkenas.github.com/coffee-script/documentation/docs/grammar.html)

~~~
endergen
You are totally correct about the C/C++ generation not being easy if I go for
making the whole language be elegantly compilable. I was thinking more of a
subset, where you can mark a module or function(Not sure about the
granularity) and it would raise a compile error if it doesn't maintain
semantics that work elegantly in both Javascript and C/C++. It's really to
allow Javascript programmers to not have to learn C/C++ and be able to
accelerate their server side code (For say large image, or file processing. Or
just expensive calculations like Pathfinding or Search-Space type stuff.) Of
course it only works elegantly for server side, but it would be future proof
for say using Native Client on the client side when or if it becomes
available.

Thanks for the pointers, I remember now finding those implementation details
when I leafed through your code a while back.

I'll check out the freenode channel when I get a chance.

------
confuzatron
What's the debugging experience like?

~~~
jashkenas
As a source-to-source language, we try to keep debugging sane by outputting
pretty-printed JavaScript that shouldn't be too hard to debug. For example,
dropping you right into the middle of the JavaScript that's generated for the
CoffeeScript Lexer looks like this:

[http://github.com/jashkenas/coffee-
script/blob/master/lib/le...](http://github.com/jashkenas/coffee-
script/blob/master/lib/lexer.js#L130)

Pretty readable. You can use a Webkit or Firebug debugger just as you would
with normal JS. It's a golden rule (with one small exception) that there are
no CoffeeScript-specific constructs or special functions added to the runtime,
no matter how tempting it might be to do so.

The single largest headache in practice is having to refer to the generated JS
if the exception is vague, and just includes a line number. But I'm not sure
that there's anything we can do to mitigate that, other than to keep the JS
readable...

