Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
Don't use CoffeeScript (tysens.us)
33 points by L8D on Sept 7, 2013 | hide | past | favorite | 29 comments


This is actually almost completely wrong information. The lower-level for loop is much more JS engine friendly than the Array methods (filter, map etc.). So unless you write JS like it's C, for the most part, CoffeeScript will probably generate more efficient code[1]. As shown in the jsperf by @mischani [2]

The only thing that's true is that CofeeScript generates some throwaway code because of implicit returns and the "everything is an expression" rule. However, I doubt that they would cause much overhead, specially with modern JS engines optimisation capabilities.

[1]: http://mrale.ph/blog/2011/11/05/the-trap-of-the-performance-...

[2]: http://jsperf.com/don-t-use-coffeescript


See my other comment. I too think that using .map, .filter, and .forEach are a bad idea. But also, if you see the code I would have written in the jsperf, I'd guess you say that I write JS like it's C.

So, good point.


Turns out the comprehension is faster on my setup:

http://jsperf.com/don-t-use-coffeescript


Yep, the Comprehension is faster in all the environments I tested:

Chrome 28.0.1500.71 on OS X 10.8.4 (map is 54% slower)

Safari 6.0.5 on OS X 10.8.4 (map is 28% slower)

Firefox 23.0 on OS X 10.8.4 (map is 62% slower)*

Opera 12.16 on OS X 10.8.4 (map is 72% slower)

IE 10.0 on Windows 7 [via VirtualBox] (map is 42% slower)

And testing the same via a node.js benchmark it says the fastest is comprehension. https://gist.github.com/Kerrick/cff3d1212c82bc804712

* Every time I load the JSPerf page on Firefox, the first run the two tests are on par, and the second (and following) runs I get map being much slower. I have to wonder if the JS engine begins optimizing the comprehension version at some point.


Function calls in JavaScript runtimes (including V8) are quite slow. Array.map/filter/forEach will always be slower than a for loop doing the same thing.

I write a lot of games and game related things in JavaScript, and this is actually a major reason why I now use CoffeeScript. Nice clean comprehension syntax and better performance.


Array.map/filter/forEach aren't just slow because of function call overhead. They have different semantics than the for loop that you'd typically write (and that Coffeescript generates), because they support things like arrays with non-incremental keys. See the reference implementation at [1].

[1] https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe...


I was going to say... I thought one of the major selling points of CoffeeScript was that it outputs JavaScript that is highly optimized for JS interpreters.


Can you run a test with the code in the article? I even said: "And that's still not ideal. We should be able to do: [code]".

I don't ever advise using map, but you can't setup your own for loop in coffeescript. Actually, in the code shown, map isn't used at all. Just .filter and .forEach.

Here is my version: http://jsperf.com/no-coffeescript-orig

The 'manual' is what I would write myself.


On a lot of setups, going by the graph there.

Firefox nightly produces an interesting test run: http://cl.ly/image/2s0p1Y3E2Z0C not really sure why that happens.


There's no evidence presented here that there's any significant (or even negative) performance impact from the way the CoffeeScript compiles these list comprehensions. Also, if your performance is constrained by a list comprehension, there's nothing in CoffeeScript preventing you from using "Array.filter" instead. By and large CoffeeScript compiles one-to-one with JavaScript and when it doesn't, the resulting code is at least reasonably performant.

I do agree that the default return behavior is probably a bad idea. It probably came from Ruby, and I can see the appeal, but I've often created bugs by accidentally using the implicit return, then adding something to the end of a function. It's not really that big of a deal - I just as a policy always use an explicit return.


Also as an aside, CoffeeScript will only bother to populate the results array if the comprehension is the last thing in the function. If there is anything else that follows and you never use the result of the comprehension, then it compiles into a simple for loop. This is because CoffeeScript can't know if you actually plan to take advantage of its implicit return in this case.

I have found I've been forced to add a dummy `return` at the end of some of my CS methods because of this. It's one of only a very few complaints I have with the language.


Hey quick question, maybe you should use map instead of filter?

http://www.dotnetspeaks.com/DisplayArticle.aspx?ID=117 (random site with example)

map is the functional equivalent of what you're trying to do there, not filter.


His criticism still stands that the JS implementation of

  (number * number for number in nums)
...is inefficient, and that it could've been translated into much more efficient JS than it was.


It's really not inefficient though. Array.map will be much slower in just about all environments.


[EDIT] - People have followed up, turns out the comprehension is faster.


fwiw, I love coffeescript. I write a game a few weeks ago in it, but I've never shown it to anyone before. Have a look here if you're interested http://quietcode.com/vectroid

I've made no attempts at all at performance tuning yet it runs very nicely in webkit browsers and not too bad in firefox.


Wave 7 - 327950, no deaths, got bored and quit first try. It's too easy! You should add difficulty levels. (I played a lot of Touhou recently so my sense of "difficult" is in a non-standard location.) Also, more enemies that shoot things that can't be destroyed, and enemies/asteroids that need multiple hits to die (maybe enemy health increases for higher difficulty / later waves).

Bugs I noticed: All the bullets in the world sometimes disappear at once. There's no pause button.

Mostly I love the controls, except friction on your ship is a little aggressive -- I think there should be no friction if you're below a certain speed, but maybe it's just my expectations from Star Control 2 (check out the FOSS version, Ur-quan Masters, with sudo apt-get install uqm if you're on an Ubuntu-like system). Also, the game desperately needs a hold-to-fire, or even toggle fire, button. Single-shot fire in a game like this is why there was a thriving turbo controller cottage industry in the '80s - '90s.


Very nice!

While playing I noticed I was able to go faster than my projectile, and I was slightly disappointed when I was unable to damage my own ship that way.


Yes, I was trying to reward the player for flying faster instead of just sitting on one spot. Projectile speed increases as your speed increases. I though damaging your own ship would just be cruel :)

You may also notice the view zooms out as your speed increases, so you have a much wider view


The stars in the background are awesome! I think it's a little hard to see your projectiles though against the background, maybe make them a little thicker?


Thanks!

Yes, it's a bit hard to see but I haven't really spent any time tuning it - been too busy. Did you nitice the little blue ships that you can shoot to get a token to upgrade your guns? There's red ships that follow you that show up every 30 seconds, and blue ones that contain powerups that show up after (I think) 10k points.


Real time (and spacebar) killer! Got to 257000 points before making myself stop. A few gameplay adjustments and multiplayer, and I bet I'd lose a whole evening to it.

The code appears to be very well-structured and readable, even though it's compiled to JavaScript. IMO, a good example for those learning to use canvas (like myself). Thanks a lot for sharing.


That's quite awesome and inspiring. Please open source it and add lots of comments


It seems that what you actually want is for CoffeeScript to have configurable backends. I agree that it's silly to generate IE6 compatible code when I know that I'm targeting node. This isn't a reason not to use CoffeeScript -- it's a reason to improve CoffeeScript.

Furthermore, as others have noted, your post does smack of premature optimization. Without numbers, most of the claims are all pretty meaningless. Judging by number of instructions is no longer a valid metric on any platform on any level of abstraction and hasn't been since the 1980s.


I like CoffeeScript and will continue to use it where appropriate.

But I do wonder why we're stuck with all the cruft to let ECMAScript be backwards compatible. Couldn't we just one time introduce a few breaking changes to clean up the mistakes in the language's design?

And if you're really opposed to that, how about the same strict versus transitional semantics we use for HTML? I'd be happy to be writing code in a clean strict subset of JavaScript.


We already have a strict subset of JavaScript, “strict mode” – see https://developer.mozilla.org/en-US/docs/Web/JavaScript/Refe.... You activate it by putting the code `"use strict";` at the top of a script or a function.


The great thing about there being so many Javascript transpilers these days is that you can pick the right language to suit your needs.

Really want / need Google Closure / the latest ECMAScript stuff? ClojureScript supports these things pretty well.

Really like Ruby (or Python) but find yourself in Javascript land? Coffeescript is right for you.

There's some interesting buzz around getting Coffescript more Google Closure compliant, which is probably the better way to go (assuming your targeting front end JS, not Node).

But yes, there are certainly places where Coffeescript generates a crap-ton of code, where if you can pinpoint your Javascript runtime (like in Node's case) you could do more, better, and faster.


This person seems to think that "less code" is "faster code".

Yes, I do have to give some credits to putting the number x number directly into the push call

Are they really suggesting

    _results.push(number * number);
is significantly faster than, say

    var result = number * number;
    _results.push(result);
Because it's not.

Though I do wonder why CoffeeScript doesn't do something like this to avoid the function call:

    _results[_i] = number * number;


Yet Another Coffeescript Rant




Consider applying for YC's Winter 2026 batch! Applications are open till Nov 10

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

Search: