I'm not so sure about that. I use it as an experienced JS developer because it makes a lot of needlessly complex JS operations simpler.
Most of those are features in ES6, so it may well go out of vogue then - I've played around a little and may well end up returning to JavaScript at that point.
The original reason for hatred towards CS in the Node community was when module written in CS started showing up on npm. If someone was trying to debug something and hunt down a problem to your module, they can't really read the code generated by CS(because it really does become a mess unless you don't abuse the syntactic sugar), and you can't debug the CS code.
Another problem occurs when you're trying to setup a sane build system for your project. It can become really tedious to use the entire build system every time you want to run your code, and even more to setup everything correctly with source maps, stack traces, minifying, etc. Just about every other module that deals with the code you write will support CS, so in many cases it is the deciding factor in which modules or libraries to use.
The original reason for me to dislike CS was because the first team I worked with using CS made so many different style choices about the code that it become unreadable. Some people wanted to use the syntactic sugar sparingly, others would use it and put everything in one line.
Take this for example:
# print all lines given
pall = (lines...) -> console.log line for line in lines
Someone might write the function like that so that it would fit on one line and be easier to call. But as it turns out, there is a lot more than meets the eye. This is the generated code: var pall,
__slice = [].slice;
pall = function() {
var line, lines, _i, _len, _results;
lines = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
_results = [];
for (_i = 0, _len = lines.length; _i < _len; _i++) {
line = lines[_i];
_results.push(console.log(line));
}
return _results;
};
Which in that case, you might as well skip CoffeeScript's for loop and do an ES5 `Array.protocal.map` call, which will do the same thing, and can be optimized a lot further by the engine. # print all
pall = (lines...) -> lines.map (line) -> console.log(line)
Which, in V8, can be shortened down to: # print all
pall = (lines...) -> lines.map console.log
That skips the whole array generation part and is much more concise and up to ES5 standards. But there are still a few more problems with the code. Look at what it generates: var pall,
__slice = [].slice;
pall = function() {
var lines;
lines = 1 <= arguments.length ? __slice.call(arguments, 0) : [];
return lines.map(console.log);
};
See a problem? We could skip the entire first two lines by calling `Array.prototype.map` directly on the arguments. But also, we've forgotten that we never needed to 'map' over the array in the first place, because we know that `console.log` will return `undefined`. I just stuck with using map over `.forEach` so it would match CoffeeScript's 'always return something' rule, and it would be ugly to have an empty handing `return` at the end. So instead, we should probably write the function like so: # print all
pall = -> Array::forEach.call arguments, console.log
This is all in all the best of all the other code, because it generates the optimal representation in JS. If you wrote code like what CS generates, then you could see and make out a ton of flaws before hand, but who dare questions the power of CS and inspects the generated code? But none the less, if you were to write your CS like that, there would be no point in CS. Still, if you wanted to cleanest possible code to be generated, you'd need to put one of those annoying empty returns at the end of the function. pall = -> Array::forEach.call arguments, console.log
return pall = (lines...) ->
(console.log line) for line in lines
return
Is going to get you much better performance in JavaScript than using the forEach method. pall = -> console.log line for line in arguments; return
would have done just fine there.One can be annoyed by `return` in tail position, or delighted by invocations-as-expressions. But not both. It's ok to choose the latter. :-)
Also, `console.log` is not a fit for map, forEach, et al. Check the parameters.
This is FUD. CoffeeScript is JavaScript, and if you come into CoffeeScript thinking it works like ruby just because it looks like ruby then you're in for a rude awakening.
Personally, I'm a fan of CoffeeScript's streamlined syntax compared to JavaScript.
For example:
describe 'when the universe exists', ->
it 'should be active', ->
expect(universe.active).toBe true
vs describe('when the universe exists', function(){
it('should be active', function(){
expect(universe.active).toBe(true);
});
});
It's no surprise that newcomers are sometimes inclined towards CoffeeScript since one the biggest obstacles for a budding javascript programmer is the seemingly incomprehensible labyrinth of brackets, parenthesis and semicolons (not to mention the confusion that ASI adds to the picture) that one must endure to grok the language. Of course, it's not really that hard to understand, but CoffeeScript filters out a lot of "syntax" making it easier for a newcomer to tackle the meat of the application. Less is more. describe 'syntax after upgrading', ->
it 'should be even meatier', ->
expect parentheses.required
.toBe false
Very tidy. describe 'when the universe exists' {
it 'should be active' {
universe.active should be true
}
}
The pre-generated assertion messages means you get `universe.active should be true` in case of error which includes actual source of the expression.I'm not sure about that; it prevents many of JS's ugly quirks: http://arcturo.github.io/library/coffeescript/07_the_bad_par... ;)
> Cleaning up the class model is generally not a good thing, since JavaScript isn't designed to have true OOP principles.
I really don't understand this. What does "true OOP principles" mean? Objects are so central to JavaScript that it has a concise syntax for object literals. It even goes to the extent of having a dynamic "this" to let any function work as a method in an object.
It has its rough edges (like primitives), yes, but they don't make it a non "true OO" language (whatever that means) IMO.
> [...] it's expressive for loops [...] shun people from using ES5 array methods like .forEach, .map, and .filter, which are a lot cleaner and more optimizable by the engine.
Thay are cleaner in the compiled JS, but Coffee's for loops are quite clean too, and they don't require a nested closure ;)
And, although i would also like native Array#forEach et al to be faster than manual for loops, that hasn't been the case in modern JS VMs: http://jsperf.com/for-vs-foreach/75
Speed and ease of development! Yes it is mostly syntactic sugar, where I wanted to make a point is that this "sugar" adds more to the language than sweetness for the sake of it. It exposes beautiful pattern that are cluttered in day to day javascript syntax. My final compiled javascript code is not the same I would have produced would I have coded directly in Javascript. Coffeescript also gives me a different approach to think about a problem.
> Things like it's expressive for loops and default arguments generate really ugly code, and shun people from using ES5 array methods like .forEach, .map, and .filter, which are a lot cleaner and more optimizable by the engine.
I use underscore which will delegate to .forEach et all it they exist... I really rarely use loop comprehension, though they can be very expressive if used correctly..
> CoffeeScript will completely obscure the way JavaScript works to newcomers
I disagree. I've installed the proper plugin (I'm on emacs, same is true for vim, sublime or lightTable), I am therefore two stroke away from the compiled javascript. Furthermore, I spent a decent amount of time a week in the debugger where the code is in JS. If I could have disliked this in the beginning, having two different languages whether you code or debug can seem unfamiliar, I actually love it. It keeps my Javascript sharpen and it gives a thorough understanding of exactly what's happening in my Coffeescript code. And that's exactly where I found a niche for Coffeescript. In my opinion, it is definitely not a replacement for Javascript, it is a cleaner, more expressive and easier way to write it, without any real overhead. Honestly, it took me minutes to understand and less than a day to feel comfortable and be efficient in Coffeescript. What I recommend to newcomers is to use coffeescript's syntax to to learn Javascript, by continually compiling down to JS and understanding what's happening. The JS output by CS isn't ugly at all, and that is a strong point. It is really possible to learn some great javascript idoms just by applying built-in coffeescript construct and understanding their value and working in JS
> JavaScript isn't designed to have true OOP principles
... Hmm right... ?
Ruby: _why hates you, and you're all just ghetto anyway
Nodejs: he and she are bad words.