

Why I'm (Finally) Switching to CoffeeScript - darkxanthos
http://codelikebozo.com/why-im-switching-to-coffeescript

======
TrevorBurnham
Some nice examples, if a bit unfair since the JS is clearly compiled from the
CoffeeScript rather than hand-coded. In fact, the last example reveals a bug
in CoffeeScript—the function

    
    
        (x, y) ->
          for game_piece in @game_pieces
            if game_piece.is_at x, y
              @held_item = game_piece
              @held_item.start_dragging x, y
              break
    

compiles to

    
    
        function(x, y) {
            var game_piece, _i, _len, _ref, _results;
            _ref = this.game_pieces;
            _results = [];
            for (_i = 0, _len = _ref.length; _i < _len; _i++) {
              game_piece = _ref[_i];
              if (game_piece.is_at(x, y)) {
                this.held_item = game_piece;
                this.held_item.start_dragging(x, y);
                break;
              }
            }
            return _results;
          }
    

Notice that _results is initialized as an empty array... and is never
modified, making it an utterly pointless return value. What's happening is
that the CoffeeScript compiler has both implicit returns and list
comprehensions, which means that it tries to return an array of all the values
in the loop. All well and good, but the compiler doesn't try to do a list
comprehension when there's a break... and yet it creates the frivolous
_results variable anyway.

Obviously I'm a fan of CoffeeScript; this is a minor bug and I expect it to be
fixed. But let's be fair in making the case for it. Well-written JavaScript
will always look better than CoffeeScript output; it just takes a lot more
work.

~~~
BMorearty
To be fair, lack of optimization by a compiler is not a bug--unless it claims
to do that kind of optimization.

~~~
TrevorBurnham
Well, there was a related inconsistency which was certainly a bug. And it's
now fixed: <https://github.com/jashkenas/coffee-script/issues/1669>

------
Stratoscope
At least for the first example, the reason the JavaScript code is so bad is
that the CoffeeScript code is equally bad. It repeats an entire for loop for
each character code!

Having a concise syntax doesn't relieve you of the duty to simplify your code.
Both the CoffeeScript and JavaScript code can be simplified considerably, as
several others have pointed out.

In fact, if you clean up the CoffeeScript code like this:

    
    
        keyMoves =
            37: 'pan_left'
            38: 'pan_up'
            39: 'pan_right'
            40: 'pan_down'
            187: 'zoom_in'
            189: 'zoom_out'
    
        document.onkeydown = ( event ) ->
            move = keyMoves[event.keyCode]
            piece[move]() for piece in game_pieces
            the_screen.refresh( game_pieces )
    

It compiles to this JavaScript code:

    
    
         var keyMoves;
         keyMoves = {
              37: 'pan_left',
              38: 'pan_up',
              39: 'pan_right',
              40: 'pan_down',
              187: 'zoom_in',
              189: 'zoom_out'
         };
         document.onkeydown = function(event) {
              var move, piece, _i, _len;
              move = keyMoves[event.keyCode];
              for (_i = 0, _len = game_pieces.length; _i < _len; _i++) {
                   piece = game_pieces[_i];
                   piece[move]();
              }
              return the_screen.refresh(game_pieces);
         };
    

And that's a quite reasonable piece of code - nothing like the JavaScript
example in the article.

Personally I would write the JavaScript version more like this (assuming I
wanted a raw for loop instead of an iterator function, perhaps for speed):

    
    
        keyMoves = {
            37: 'pan_left',
            38: 'pan_up',
            39: 'pan_right',
            40: 'pan_down',
            187: 'zoom_in',
            189: 'zoom_out'
        };
    
        document.onkeydown = function( event ) {
            var move = keyMoves[event.keyCode];
            for( piece, i = -1;  piece = game_pieces[++i]; )
                piece[move]();
            the_screen.refresh( game_pieces );
        };
    

But I certainly don't see anything very wrong with the CoffeeScript-generated
JavaScript, once the original CoffeeScript code is improved.

------
pilif
When you directly compare coffeescript to JS and looking at more or less the
same code (but of course it's very unfair to JS to use coffee compiler output
instead of hand written JS), you won't find much of a difference aside of the
small syntax changes.

But once you are used to coffee, your code will start to look very different
from pure JS code. Coffe encourages you to write even more, even smaller
functions due to its lean syntax.

This new coding style that emerges (at least it began to emerge for me and a
coworker) is infinitely more readable than JS, even more so when you look at a
direct translation.

My takeaway from this is two things:

1) coffee is cool. Just give yourself one time to adapt. At first everyone's
code in $NEWLANGUAGE looks like code in $OLDLANGUAGE until you get used to the
common idioms in your new language.

2) The general syntax of a language can have a huge effect on your code style
which in turn can have a huge effect on overall readability.

~~~
darkxanthos
I haven't seen that yet but I can imagine it happening. I love Javascript but
coding lambdas always felt ugly enough that I used it more in C# than JS. It
is definitely true CS fixes that for me.

------
gmac
I find CoffeeScript pushes programming in the browser over the crucial tipping
point between Not Fun and Fun. (I'm almost embarrassed by how much of a sucker
I am for syntax, but there it is).

~~~
masklinn
> I'm almost embarrassed by how much of a sucker I am for syntax, but there it
> is

It's interesting how so many people profess love for CF's syntax, where I have
such a dislike for it (to me, it looks like a magpie language: rather than a
whole design it's cobbled from shiny pieces taken from all over the place; the
way some features are "integrated" are close enough to yet far enough from the
source language that it lands straight in my uncanny valley; it's drawing back
from the OO/Func movement of the JS community back into procedural and
statements-based something fierce; the target language leaks heavily through
such things as the thin v fat arrows; and finally it draws back from things I
think are genuinely better features of javascript, such as explicit scopes)

~~~
M1573RMU74710N
> it's drawing back from the OO/Func movement of the JS community back into
> procedural and statements-based something fierce

This statement is completely incorrect, the truth is actually the exact
opposite.

First I would note there is no such thing as a statement in Coffeescript.
__Everything is an expression __... this may seem like a minor point to some,
but it's actually quite a powerful difference. As with a lot of the things CS
adds, It's hard to appreciate the boost in expressiveness until you start
writing a lot of code with it.

If you want to talk about functional programming, expressions rather than
statments count as __1 whole point out of 9 __for PG's "list of things that
are awesome about lisp".

Another important aspect of functional programming is lambdas, JavaScript does
not have "real lambdas" because of the lack of implicit returns and the
aforementioned quality.

By adding them, CS get's you much closer to real lambdas. This combined with
the light syntax for functions __encourages __one to program in a much more
functional style.

These qualities enable say, quick and easy decorators:

    
    
        logged = ( f , named_f ) ->
            if named_f? then [ f, name ]  = [ named_f, f ] else name = "function"
            # decorated function, to be returned
            ( args... ) ->
                console.log "#{name} (#{f.length}) with #{args.length} args."
                f.apply @, args
        
        # random function, note our decorator preserces "this"
        foo = logged ( x ) ->
            console.log( @[x] + "" )
    
        # random function that calls other function, our logging lets us trace the calls
        # this one provides a name
        bazz = logged "bazz", ( x ) ->
            foo.call @, x
        
        # test
        bar =  fizz: "buzz"
        bazz.call bar, "fizz"
    

Note also how splats simplifies this operation. Destructuring and the
existential operator makes the logic in the decorator function a little
cleaner. String interpolation makes the logging easier.

Additionally the use of implicitness really makes it shine and fit together
well, rather than being mere eye-candy. There's no wrapping in parens to
decorate, making it harder to mess up, easier to modify, and easier to parse
visually and perhaps programatically.

I think a lot of people are deceived when it comes to CoffeeScript, they see a
lot of little things which seem nice...but individually they seem pointless or
minor. They are deceived on two parts: a lot of these "little things" are
actually quite powerful on their own, and additionally they mesh in a way that
is greater than the sum of the parts.

All these little nice things can add a powerful boost to expressiveness and
once you spend some time with them it really changes how you think and write
code. That's another thing I would note is that CoffeeScript is for people who
want more expressiveness/find these things more expressive. If you are looking
for something else, or think in a way that has an impedance mismatch with the
CoffeeScript philosophy, obviously you should look elsewhere.

(If anyone's curious, this decorator makes it so every time a decorated
function is called, it logs the function's name if provided, the number of
defined arguments it takes, and how many it was actually passed.)

I would also note that scopes function the same in CS as they do in JS, the
only difference is that in CS you cannot shadow variables from an enclosing
scope, and there are no implicit globals.

In terms of OO, CS adds syntactic sugar for perhaps the most common
inheritance pattern in JS.

I would argue both of those are _good_ things, though I respect other people
might think otherwise.

------
eekfuh
> var game_piece, _i, _j, _k, _l, _len, _len2, _len3, _len4, _len5, _len6, _m,
> _n;

I dont see why he didn't use do "var game_piece , _i , len;" He doesn't need
multiple i's nor lengths. The JS example is just a very poor example of
coding. (in fact he could of just simplified it further down by having one
loop and a variable to the method, to be executed on those pieces.)

CoffeeScript is very nice, but I want to see examples of why to use it that
will actually save me time. Compared to the examples, there are better ways to
code and tons of easy ways to do OO with certain frameworks/toolkits.

~~~
reaktivo

        var keydown_action_map = {
          37: 'pan_left',
          38: 'pan_up',
          39: 'pan_right',
          40: 'pan_down',
          189: 'zoom_out',
          187: 'zoom_in'
        }
        document.addEvent('keydown', function(event) {
          var action = keydown_action_map[event.keyCode];
          game_pieces.each(game_piece[action], game_piece);
        });

~~~
rimantas
This can be written like this too:

    
    
      keydown_action_map = 
            37: 'pan_left'
            38: 'pan_up'
            39: 'pan_right'
            40: 'pan_down'
            189: 'zoom_out'
            187: 'zoom_in'
    
      document.addEvent 'keydown', (event) ->
        action = keydown_action_map[event.keyCode]
        game_pieces.each game_piece[action], game_piece
    

If you can write terse code in JS you can write it even more terse way in CS.

~~~
masklinn
Where "more terse" means "removing a useful keyword and replacing parens by
spaces".

Not exactly impressive (and coffeescript's symbolless maps read horribly
badly, imo).

~~~
rimantas
Which keyword is useful? Var? CS will put it back at compile time, don't
worry. And it will do it in more consistent manner than many coders will
manually. I have no problems with symbolless maps, and CS will save your ass
from being bitten by IE because of stray comma.

~~~
thezilch
I protect my ass with VIM -- any "IDE" likely has an equivalent.

    
    
      au BufWrite *.js mark` | silent!%s/,\(\_s*[}\]]\)/\1/g | norm``

------
yason
The examples weren't too enlightening.

In the first example I would have written the original handler like this, for
example. Written more concisely it doesn't present an immediate need for
shortening or clarification by CS:

    
    
      document.onkeydown = function(event) {
          var key_to_func = {
    	  37: "pan_left", 38: "pan_up",
    	  39: "pan_right", 40: "pan_down",
    	  189: "zoom_out", 187: "zoom_in"
          };
          for (var i in game_pieces)
    	  game_pieces[i][key_to_func[event.keyCode]]();
          return the_screen.refresh(game_pieces);
      };
    

The class example is better but I haven't found much use for the JavaScript
prototypes to build class-like constructs. Instead of using prototyping I
generally just create objects and shove stuff into them. YMMV.

Last example is merely a transformation of the first version. The constructs
used are quite similar: it would have been nice to see CoffeeScript transform
the actual paradigms used in the code. The CoffeeScript version still reads
like JavaScript, just with slight syntactic sugar.

Mere syntactic sugar might actually be the core idea of CoffeeScript (instead
of landing a somewhat higher-level language on top of JS) in which case the
example illustrates nicely why the gains from switching from JS to CS are
mostly cosmetic. You can compress your code conceptually much better if you
just write JS more functionally, i.e. write a few quick functions to provide
map/filter/reduce and some helpers.

------
tootie
I absolutely don't get it. The CoffeeScript code looks way to obscure to me. I
don't need more punctuation marks. List comprehensions can just be written in
JavaScript very easily. jQuery provides them OOTB. Improved switch statements
seems pointless when you can use a dispatch table. I'm all for better OO
syntax, but I'd much prefer something slightly more verbose and transparent.
This looks like an attempt to put Perl in the browser.

------
podperson
If there's a case for coffeescript over simply biting the bullet and learning
to love JavaScript, this blog post doesn't touch it. If anything, well-written
JavaScript code would be cleaner than his coffeescript examples (as noted in
some commentsl although no doubt his coffeescript could be improved too).

------
dancavallaro11
I hate to harp on one minor point that he made, but I strongly disagree with
his assertion that you could dump CoffeeScript, stick with the generated JS,
and be happy with it. The generated JS he showed in those examples was
terrible, and would be a maintenance nightmare.

------
nextparadigms
Anyone planning to make a "CoffeeJava" language?

~~~
groovy2shoes
Had a look at Mirah? <http://www.mirah.org/>

------
deleo
CoffeeScript is interesting, but to be more so it shouldn't be limited to
browser scripting. Until it doesn't become more general purpose i'll just
stick to Python or Node.js

~~~
TrevorBurnham
CoffeeScript and Node.js get along fantastically. When the "coffee-script"
library is loaded, you can even "require('foo.coffee')" directly, making it
easy to mix-and-match JavaScript and CoffeeScript files.

Sam Stephenson, the creator of Prototype.js, has been doing all kinds of
awesome things with CoffeeScript and Node.js. And there's a chapter of my book
on it...

~~~
deleo
So how do you write a basic web server in CoffeeScript?

~~~
jashkenas
The Node.js "Hello World" web server:

    
    
        http = require 'http'
    
        server = http.createServer (req, res) ->
          res.writeHeader 200, 'Content-Type': 'text/plain'
          res.write 'Hello, World!'
          res.end()
    
        server.listen 3000
    
        console.log "Server running at http://localhost:3000/"

~~~
deleo
Well but this isn't written in CoffeeScript. This is what I was saying:
CoffeeScript can work alongside Node.js but can't access the filesystem. It
might be good in its own right for DOM scripting and such but it doesn't open
any more doors than Javascript.

~~~
stdbrouw
Then what is it written in, if not CoffeeScript. You're somehow very very
confused about things :-)

~~~
deleo
No I think you are confused. That is Node.js syntax. Ok now show me how you
open a file on the filesystem in CoffeeScript then.

------
skeptical
I fail to understand how this gets to be on the first page of HN, sided by
links to the usual great stuff. My opinion worths for what it worth, but I
would say this is a rather bad article and show some poor programming
examples.

As many pointed out (five proper versions of the first snippet so far), the
examples are not really valid.

I do not necessarily agree with the trend of criticizing javascript of being a
language that needs to be fixed. Quite frankly, it is a proper language.
Coffescript introduces some practical sugar, class construct being IMHO the
best plus as javascript class definitions are rather verbose. CS object
notation is another neat advantage. Many other things on coffeescript appear
to be concepts that for some reason are fashionable these days such as the
arrow or the conditions after the statement.

I write javascript everyday and I absolutely don't feel like there are
anoyances which need to be taken care of urgently. It's a language as
enjoyable as most. Cofffescript does look cool and I do plan to use, at least
for fun if not for any other reason. But saying that is the missing piece, or
that is the long expected replacement for javascript, sounds like fanboyism.

~~~
masklinn
> I fail to understand how this gets to be on the first page of HN

Same reason every shitty go article out there reaches HN's front page (or
reached until pretty recently), same reason /r/prog's frontpage is cyclically
full of a single technology or language: it's what most denizens of the place
currently have a hard-on for.

