Let's all take a moment to reflect on the elegance of the grammar.coffee file [0]. Notice how the function named 'o' provides simplicity as it plays well paren-less function calls.
It's been around since 2009, which makes it positively ancient, as far as popular compile-to-JS languages go. But mostly, it's more or less "finished". There are some small new features that will come down the pipe (support for 'yield' and other new ES6+ features, continually improving source maps, and so on), but all of the big bones of the language are done at this point. So no news is good news.
I think CS is too similar to JS in it's current an upcoming versions to stay relevant in the future. After Harmony the few differences between JS and CS will be trivially fixable by a few macros like Sweet.js.
Personally I moved to LiveScript as it gives me much more syntactic support for functional semantics, without requiring runtime support like ClojureScript (although I'm looking into ClojureScript as well, just not using it in production). But I'm in a privileged position because I could make that choice myself; I think not many people could do this. And they don't, which means if they switched to CS they're effectively stuck with it for some time.
Which, yes, makes CoffeeScript rather mainstream language :)
Agreed, but where do "different" begin and where it's still "just JavaScript"? Almost all patterns supported by LiveScript syntax are already present in JS and CS as a libraries. For example the cascade syntax in LS is almost the same as what raganwald's KaTy.js provides semantically. Similarly, function composition is supported by more than one library (Underscore.js has "compose", for example) and currying is also easily implemented in both JS and CS (see raganwald's writings, for example http://raganwald.com/2013/03/07/currying-and-partial-applica...), so once again the only thing LiveScript provides is a bit of syntactic sugar. Is it really that different from Coffee or JS?
In my opinion LiveScript is as similar to JS as Coffee is, just where CS adds syntactic support for more imperatively and OOP oriented constructs LS focuses on functional and declarative ones. Which are all expressible in JS.
Actually "different" would be ClojureScript, Amber or Objective-J. Or any number of compile-X-to-js projects.
I never really bought the "javascript syntax is good enough" argument against Coffeescript. The whole point is that CoffeeScript's defaults encourage good parts JS rather than the bad parts that JS's original syntax encourages.
Hip? Dunno, I moved onto ClojureScript years ago. ;)
There has been a development of hate towards CoffeeScript in most JavaScript communities. CoffeeScript seems to be very popular in the non-JS communities that need to write JavaScript, like in the Ruby and Python web development communities. CoffeeScript was designed for non-JS coders to feel a lot more comfortable writing JS.
CoffeeScript was designed for non-JS coders to feel a lot more comfortable writing JS.
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 thing about CoffeeScript is that it makes it a ton easier to reason about doing operations like default arguments, pattern matching or expressive for loops. When you don't see the messy code generated from its syntactic sugar, you don't think its a problem. But when it comes to best practices, long term decisions and performance, CoffeeScript will stab you in the back.
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:
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 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:
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.
Much ado about nothing. CoffeeScript performance in general is a lot better due to non emulated foreach constructs which plague javascript today. Like noted there are ways of teasing the compiler in generating very friendly looking js code, but honestly if you are tripped up by a simple for loop in coffeescript maybe looking at code isn't your cup of tea.
There has been a development of hate towards CoffeeScript in most JavaScript communities.
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.
I'm also not so sure about the "non-JS coders" part. As a proficient Javascript programmer, I absolutely love CoffeeScript. I even recommand it to learn the good parts of JS when you are completely unfamiliar with it.
I think there is a lot more than synctactic sugar to Coffeescript. It makes obscur or verbose JS patterns really easy to use.
My code generally compiles down to up to twice as much JS code. Yes the compiler outputs somewhat verbose JS, but I can't deny the speed and ease I've gain with it. And it is only my first professional project using it.
What speed and ease to you gain with it? CoffeeScript won't get you any performance; if any, less. Making obscure or verbose patterns easier to use is syntactic sugar. Part of the thing about CoffeeScript, is that there are more bad parts that it introduces than prevents. Cleaning up the class model is generally not a good thing, since JavaScript isn't designed to have true OOP principles. 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. If you're ever trying to check the existence of a variable, then you've already probably made a bad design choice; but you won't realize it because CoffeeScript encourages the pattern. Also, CoffeeScript will completely obscure the way JavaScript works to newcomers, and will confuse them and encourage them to use the syntactic sugars in place. The syntactic shortcuts were originally there to make it easier for those who really needed to use the nasty things to achieve it. Now, a CS user would use them because they're there. If you teach a ruby programmer CoffeeScript in order to introduce them to JavaScript, they're not going to be able to know the differences well enough to appreciate and understand them.
> 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
I think you're referring to OOP in the literal, "program uses objects so it's object-oriented" sense, whereas parent is referring (more accurately, IMO) to the common, "classical" understanding of OOP as implemented in Java/Python/Ruby. When people say OOP, that is what they are referring to, and in that sense parent is correct, JavaScript is not really OOP. And in the broader JS community, heavy use of OOP is very uncommon.
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
I don't mind what it does to improve the class model, but I dislike how it breaks certain C idioms. It's very awkward to write an expressive loop, for example.
I don't know if it's "hip," but I think it has a well-established place in the web development ecosystem, especially since using it is one of the defaults in Rails.
Personally, I enjoy it and have been using it to build a fairly large Angular application (Java backend, oddly enough.) I've found that Coffee and Angular complement each other nicely.
As of right now, they're just concatenated and minified into one file. This made more sense earlier in the project, and now I'm looking into other options, including Require.
I used it for a while, on a large project, and eventually came to hate it. I try to write as clean code as ppossible but still found the resulting mess of words, commas and arrows floating around at differing indentation levels to be much harder to read.
To me, even though javascripts syntax can be annoying, it's parentheses provide a certain amount of structure to the code.
CoffeeScript played an important role in the development of ES6, but looking forward, it seems to have a same-but-different set of features vs. actual JavaScript, which may doom its future.
A doom dependent on full adoption of ES6 could easily be a decade out, to be fair. There aren't, as far as I know, any browsers that expose ES6 without non-standard compile/runtime flags, and we have to wait until there's enough adoption that the % of people using pre-ES6 browsers is negligible.
Hell, I'm still waiting for Array::map to be dependable.
MDN publishes correct polyfills for ES5 Array functions like map, reduce and forEach. I think it's worth shipping those and using them now.
Ultimately though, wouldn't you want to use a js preprocessor that lets you write full spec ES6 and compiles down to ES4 or whatever your runtime target is? That's available today, and it doesn't confuse the meaning of class, fat arrow, variable scoping, etc.
JavaScript will never adopt CoffeeScript syntax and will retain quirks for backwards compatibility (such as the == operator). CoffeeScript may very well settle on features, but only JavaScript's death could doom it - and that seems unlikely.
I too resisted the initial cargo cult culling that happened in yesteryear. I picked up coffee-script probably a year or two later. I was focused on learning other skillsets prior. After finally spending the time to pick it up it's been an invaluable skill. From learning to productivity, it's a win.
Still seems to be getting a lot of use and I'd certainly choose it myself over vanilla javascript.
But now that decent alternatives with support for static types like Typescript and Dart exist, I'd choose either one over Coffee just for maintenance reasons and improved tooling support.
I think it counts as mainstream. We've basically migrated entirely off Javascript at Narrative Science, we've got a whole bunch of server- and client-side CoffeeScript. It and Python are our two first-class languages.
I think it has a deep saturation in many applications where the server is in something other than Node. The shininess may have worn off a while ago, but I think it is still entirely relevant.
Updated the wrapper.js script we use to run uncompiled coffeescript files in node. It now checks for the existence of .register() and calls it if it's available.
I absolutely love CoffeeScript, with how it structures classes and functions makes sense (plus the python like syntax was a big plus for work). JavaScript seemed to unorganized, unclear, and cluttered for big projects.
I do a fair amount of coffeescript work and every time I see the compiled source I'm so glad that I'm writing in coffeescript. It's not just that it makes certain JS gotchas almost non-issues (almost! there are still several things that can trip you up), it's that it makes clean, concise and correct programming so much easier. There are a lot of things, like curried functions (`f = (a) -> (b) -> result`) or testing for membership in a list (`if foo in [a, b, c]`) which one is much more likely to use in coffeescript than JavaScript because the syntax is so much nicer. Having good syntax doesn't just make it easier to read and write, it promotes good habits and discourages bad ones.
> Leading . now closes all open calls, allowing for simpler chaining syntax.
I feel like this is an important improvement, but I don't really understand what it means. Can someone elaborate on what this means and how it works? How did things used to be different?
You used to have to do this:
$('body')
.click (e) ->
$('.box')
.fadeIn('fast')
.addClass('.active')
.css 'marginRight', '10px'
Note the extra ( )s, if not used, the next method call is not recognized as a method call but rather part of the previous call's argument. The last method call did not and does not need to be closed with ( ).
This is hugely important for libraries like d3 with super long call chains.
>When requiring CoffeeScript files in Node you must now explicitly register the compiler. This can be done with require 'coffee-script/register' or CoffeeScript.register(). Also for configuration such as Mocha's, use coffee-script/register.
Since I have not been specifying my CoffeeScript version, I have a feeling this update is going to break a lot of my Node.js code. Am I right?
What does %% do? The documentation says: a %% b is the same as (a % b + b) % b, but what is the difference between "true mathematical modulo" and the standard modulo?
The "standard modulo" is actually a remainder operator, and is a js-specific thing. Most languages implement the "true mathematical modulo", aka modulo.
One reason this is useful is if you want an array to wrap around. With modulo, you just index on `index % length` and all is well. But with remainder, this will only do what you want for `index >= 0`, because it can give negative outputs, given negative inputs.
Its not unheard of. There's another niche language called "Python" that does exactly the same thing. Comments are `#`, as anyone using a unix shell would expect.
CoffeeScript has always used a single # instead of double // for comments.
In previous versions `//` compiled into an empty regular expression – something a little more difficult to express in JavaScript. But also something pretty much useless — hence the willingness to use it as an operator here.