

Brief Video: Rewriting JavaScript into CoffeeScript - jashkenas
http://ryanflorence.com/2012/javascript-coffeescript-rewrite

======
threecreepio
I both like and use CoffeeScript, but the video does show off one thing that i
personally quite dislike about it.. Implicit returns (which I love in ruby..).

When trying to port over some applications to coffeescript, I had to revisit a
whole lot of my functions to add in an empty return; line after code like:

    
    
        test: (m) ->
          m(i) for i in this.set
    

Since I didn't really expect them to build up and return arrays of the results
of invoking m, which at times could result in a method that would generate
gigantic arrays that I would subsequently throw away, killing my performance.

I probably _should_ have expected that, sure, and if you don't have to deal
with too much data it probably won't matter.

~~~
jashkenas
Out of curiosity ... if you love implicit returns in principle, then why would
you dislike them in this context?

Certainly, you need to keep in mind the return value of a function while
you're writing it -- if you don't want to return any value, then just
"return". And it's definitely something that you need to keep more in mind
while porting JS than when writing code from scratch. But given all that,
would you really prefer explicit returns in CoffeeScript?

~~~
threecreepio
I hadn't actually looked at the issues list to notice that this and similar
issues have already been brought up plenty enough, so, sorry about that. And I
do like implicit returns, and they're one of the main reasons I'm using
CoffeeScript in some projects.

What I was trying to express was that I don't generally run into this issue in
ruby because the similar looping constructs don't behave this way, and don't
carry the same kind of unexpected side-effects:

    
    
        def test(lst) lst.each{|i|do_stuff(i)} end
    

this method will return "lst" back to me, it won't create any new arrays of
the do_stuff(i) results, the same goes for for/while loops, whereas:

    
    
        def test(lst) lst.map{|i|do_stuff(i)} end
    

will return the block results. The key difference being that the map method
_always_ creates an array and returns it, even if I would have a return;
after, so it is consistent.

The only situation where I get into the problem is with looping, and after
some time using CoffeeScript, only rarely, so it may just be one of those
things you have to put up with. Still crops up occasionally after refactoring
though.

I would not want to get rid of implicit returns, and would far rather continue
dealing with the loop problems than that. Would just love it if those weren't
the only options.

------
zzzmarcus
You can also cut and paste it into this site: <http://js2coffee.org/>. It's
not always perfect, but it will get you 95% of the way there.

------
jashkenas
For more in this genre, see: <http://www.screenr.com/xd0>

------
nxn
Is that code really valid CoffeeScript? Last I looked, and I admit that the
last time was months ago, 'on' was a reserved keyword (an alias of 'true') and
I had to do some quite ugly hacks to be able to have a method named 'on'. This
may have been related to dynamically adding the method onto the prototype of
some constructor rather than defining it in a class.

Besides that, I still get feelings of discomfort when thinking about rewriting
JS to coffeescript when knowing that the compiler will just write it as JS
again.

EDIT: Tried it. In this case it seems to works.

------
gps408
Can someone explain the 'same name key:value shortcut' feature?

~~~
jashkenas
It's a DRY thing. Often in JS, object literals assign their keys to values of
the same name -- you'll see a lot of this:

    
    
        $.ajax(url, {
          data: data,
          contentType: contentType,
          success: success,
          error: error
        });
    

... not so nice. So as a first stab, you can clean it up like so:

    
    
        $.ajax url, {data, contentType, success, error}
    

... but it's _especially_ nice in the context of destructuring assignment,
like for your Node.js imports, for example.

    
    
        {spawn, exec} = require 'child_process'

~~~
gps408
Nice. Thanks Jeremy.

------
munificent
This is very cool, though I personally find postfix flow control confusing to
read. The postfix loop with destructuring is especially odd to me. As I read
left to right, I see variables that don't exist "yet" until I get to the later
loop clause.

This is probably just a familiarity thing and I would get used to it, but
compared to all of the other changes in the video which I think are pretty
clean that stood out to me as a bit... iffy?

~~~
jashkenas
Agreed. I think there's a bit of LOC-golfing at work here. That loop is more
nicely written as:

    
    
        for {handler, context} in @events[topic]
          handler.apply context, args

------
ecto
But... why?

~~~
chc
If you look back a little ways, you'll see he previously asked the same
question in an earlier article. I think this video is sort of his answer.

