You may have been misinformed -- the values of direct, raw, fast code are a big part of the reason why CoffeeScript works the way it does, and why many scripts can end up running faster after getting ported to CoffeeScript. The golden rule of CoffeeScript is to avoid adding any library code to the runtime, and to avoid introducing any special calls, to the greatest extent possible.
Many folks rely on a "forEach" (or "each") iterator for all of their loops over arrays, because it's convenient. Unfortunately, it's also a very slow way to write an inner loop. CoffeeScript's comprehensions expand into regular JS loops over arrays and objects, so you get native speed, without the hassle. This:
for item in list
sum += item.amount
Compiles into this JavaScript:
var item, _i, _len;
for (_i = 0, _len = list.length; _i < _len; _i++) {
item = list[_i];
sum += item.amount;
}
The small bug in your code actually makes a good case for using the more concise syntax of coffeescript to help avoid those kinds of errors, while generating code that's just as efficient.
for i in [0...list.length] by 1
sum += list[i].amount
to get equivalent compiled output.
I've used C and Java since high school, but I'm happy to be rid of that old `for` syntax. And I love that curly braces means only one thing in CoffeeScript: "I'm defining a new object with these key-value pairs."
I mean "direct" as in as few abstractions as possible, and "raw" as in as close to the metal as possible.
I am used to writing native loops in Javascript, so taking your example I would usually write:
var length = list.length;
while (length--) sum += list[length].amount;
Here, the hand-tuned Javascript is 38% smaller than the compiled CoffeeScript, albeit a few more characters to type than the source CoffeeScript. The reverse while loop is also slightly faster to execute than the for loop in the compiled CoffeeScript.
And I know that forEach loops incur additional overhead so I use them when it's convenient, when the arrays are small. I don't need to compile my Javascript just to keep from accidentally using forEach in situations where native loops would be better. I usually try to think about these things when I code and I enjoy being able to decide when to use a forEach loop, when to use a reverse while or a vanilla for loop etc. Sometimes, it's good to be specific in how you write code.
Furthermore, I would write for loops more succinctly than the compiled CoffeeScript in your example. You can use a for loop to declare the "item", "_i" and "_len" variables inside the loop itself without writing them twice. There's no need for the temporary item variable and the for loop is then short enough to be on one line:
for (var _i = 0, _len = list.length; _i < _len; _i++) sum += list[_i].amount;
Here, the hand-tuned Javascript is 32% smaller than the compiled CoffeeScript.
I don't mind typing a few more characters if it means I can get closer to the code and serve smaller, faster code to users (or servers). If it means just one less deployment step, or one less 3rd party dependency, or one less leaky abstraction, it's worth it. I think this proves true in the cases above, where CoffeeScript certainly makes the compiled code longer, slower than it needs to be.
Yah but your example for Javascript uses some dubious code. Did you know that "for .. in" loops are also native to Javascript? Why not use one for JS, why only Coffeescript? Also, it seems like you are doing some useless variable declrations.
Let me rewrite it for you:
1)
var list = [{amount:2}, {amount:5}], i, sum = 0;
for (i = 0; i < list.length; i++) {
sum += list[i].amount;
}
console.log(sum);
2) Or let's go even more simple...
var list = [{amount:2}, {amount:5}], i, sum = 0;
for (i in list) {
sum += list[i].amount;
}
Personally, i don't find anything difficult about that.. Actually looks incredibly simple. What are you actually saving by using Coffeescript...? Some brackets, parens and a semi-colon? I don't know, those are just second nature for me. I've never really stopped and thought, "wow, if only I didn't have to type these extra parens, this is really killing me..."
The other "complexities" in the compiled JavaScript are there for perf reasons (not accessing the "length" properties in the condition portion of the for loop, for example).
Your comment underlies why some users find CoffeeScript useful in dealing with some of the idiosyncrasies and performance minutiae associated with JavaScript.
Right, for..in is not the same as iterating through all elements in an array. Understood. But it works excellent in the example the OP created and in my follow-up example.
And I agree that accessing the length property in the conditional is not ideal.
I guess it comes down to this for me: I don't feel that Javascript has an unduly burdensome list of common idiosyncrasies to justify developing in a 'different language'/syntax that compiles into javascript and changing my development workflow to reap said questionably useful benefits.
Many folks rely on a "forEach" (or "each") iterator for all of their loops over arrays, because it's convenient. Unfortunately, it's also a very slow way to write an inner loop. CoffeeScript's comprehensions expand into regular JS loops over arrays and objects, so you get native speed, without the hassle. This:
Compiles into this JavaScript: