Hacker News new | past | comments | ask | show | jobs | submit login
CoffeeScript: The beautiful way to write JavaScript (amix.dk)
156 points by jashkenas on March 8, 2011 | hide | past | favorite | 82 comments



I can't shake the feeling that people that like CoffeeScript are those that don't "get" JavaScript (e.g. CoffeeScript's notion of a class, whereas JavaScript has none -- let go an embrace the prototypal object model). Further, most (if not all) of the examples of the problems with JavaScript are null and void. A language that combines paradigms? Most do. Sure, the name sucks, but that's hardly an issue.

I understand that syntax may be more convenient for some, but this is indirection, and is a source of complexity that may impede collaboration from other devs more familiar with JavaScript.


I think the opposite: people you get CoffeeScript are more likely those who really get JavaScript. It's turning JavaScript into the language it was supposed to before before the marketers got their hands on it and "javafied it".

In fact, Brendan Eich has taken a bunch of it's features and they will be included in the next version of JS (woot!): http://brendaneich.com/2011/01/harmony-of-my-dreams/

http://www.aminutewithbrendan.com/pages/20110131


Perhaps this isn't the best forum for such a philosophical debate, but the notion that because you have prototypes in JavaScript you don't have classes is just plain wrong.

Every single time you see JavaScript prototypes used effectively, you'll find that they follow a classical pattern: A constructor function serves as the class object from which new objects are instantiated. Syntax like instanceof ("object instanceof class") gives this away. So do all of the built-in JavaScript classes: String, Function, RegExp, Number...

If it's an abstract object that defines common properties for instances, it's a class object, regardless of what you choose to call it. JS prototypes just expose the implementation mechanism, and CoffeeScript just provides you with a convenient way to manipulate the prototype chain.


I prefer coffeescript for the reduced line noise, particularly around lambdas, loops/comprehensions, and object literals. I find the shorter lines and reduced line count* allows me to notice api flaws more easily, so I tend to do my api design in cs. I generally don't use the class construct unless the library I'm working with uses the same pattern (e.g. yui3). It's pretty much just syntactic sugar that simplifies the code at the expense of complicating the toolchain. I think it's worth it but I've met plenty of people who don't.

* In js->cs rewrites I usually wind up cutting the line count in half, but most of that is eliminating all the stray closing brackets on their own lines and collapsing if statements into single lines.


CoffeeScript is javascript so prototypal objects still work as expected. They just went ahead and threw in classes if you want them, since there are already many javascript libraries that provide them for people who either are used to / want classes or to make it easier to port existing code.


coffescript !== javascript, and it never will === javascript.


Please elaborate. It's easy to match generated Javascript to it's corresponding CoffeeScript source. There's a lot of syntactical sugar, but there isn't much that isn't just a handy shortcut. I used something kinda like CS's class system in JS before I even discovered CS.


I have to say that by using cs I learned a lot more about js. Maybe for old js cats it doesnt matter, but I only used js occasionally before, and now it became one of my favorite languages (I use with node, and I write all my node stuff in cs).

One particular example that changed everything for me was the natural and simple way I could build the typical callback constructs with -> and => , so they almost look like blocks in ruby, and feel way more natural as a control construct, and I didnt have to stack lots of })}); and so on.

If you're rather new to something, the ease of use and the simplicity and readability speeden up the learning process extremely.

That being said, there are also a couple of things in cs that are kind of silly.. like using 'for i in my_array', but 'for k of my_dict', and stuff like that, that are really hard to debug.

Although, in terms of debugging, the fact that it gets compiled and possible errors are early detected and a canonical js is generated also saved me lot of time, in particular with IE ;-)


To explain the reason for the "in/of" distinction...

"for item in list" vs "for key, value of object" is an unfortunate necessary evil. It would be great to use the same keyword, "in", for both types of loop, but I'm afraid there's no way for us to know at compile time if "list" or "object" is really an array, or really an object.


The fact that cs is doing this 'the right way', meaning safe for all environments, as you have explained below, is one of the reasons I like it.


I'm curious, why do you need to make a distinction? Is there some other feature of CS that depends on it? Certainly 'for key, value of array' could be implemented with numerical keys. If using just 'for value of dict' is allowed that would also work fine.


We need to make a distinction because we want to have arrays be iterated over with:

    for (var i = 0, l = list.length; i < l; i++) { ... }
And objects iterated over with:

    for (var key in object) { ... }
Using a "for-in" loop over a JS array isn't acceptable, for performance and semantics reasons, and neither is sniffing at runtime to determine whether the object passed is an array, or an object.

Ideally, JavaScript would have supported a single iteration protocol for both arrays and objects from the get-go, but alas...


I'm new to programming and learned a little bit of javascript lately. I'm going to do a mini project on Node just to give myself an excuse to learn more programming.

If you dont mind my asking, how would i go about using CoffeeScript with Node?


If you build those simple 1-file-testservers with node, simply write them in coffee and then start them like "coffee myserver.coffee".

If it's more elaborated, you might want to set up some kind of build process and then use the generated js files. You could use a simple Makefile and compile your coffee files with coffee -c -b.


Oh, i forgot: You can add the --watch switch and get your scripts compiled on save.


I'll try that. Thanks!


I don't think many use CoffeeScript because they don't "get" JavaScript. I think they use CoffeeScript because it gives them a much better JavaScript and makes them more productive and "happy".


I don't agree with your opinion at all. Your claim that coffeescript is somehow 'better' than javascript is just false. You prefer one syntax, fine, but don't assume that it is somehow 'better'. I prefer Javascript. I do not prefer Coffeescript at all, and I get javascript, and have gotten it for 14 years.


When targeting Node, one runtime and ES5, vanilla JS isn't so bad. Writing JS for browsers is painful, and CS addresses a lot of those pains.

A function that does nothing useful but illustrates some pain points:

  function frob(obj) {
    var rest = [].slice.call(arguments, 1)
      , results = []
    for (var k in obj) if (obj.hasOwnProperty(k)) {
      v = obj[k]
      if (blurgh(v, rest)) {
        results.push(v)
      }
    }
    return results
  }
This is roughly the same function in CS:

  frob = (obj, rest...) -> [v for v of obj if blurgh(v, rest)]
That's at least 5x more expressive. And it works in browsers, node, and pretty much every other JS environment. I don't write CS but you have to be blind to deny its benefits.

edited: Fixed the CS to iterate over keys of obj using 'of' based on other comments here


Couple of small issues. You probably want "when" instead of "if". The if applies to the whole loop, not to each element. Also, the braces around the comprehension is a pythonism I guess? It means it puts the result into an array, so you get [[<stuff>]] instead of just [<stuff>]. I've made that same mistake a bunch of times.

Nitpicking aside, I totally agree about the expressiveness. I find myself writing about half the number of lines in CS as compared to JS, and the syntax fits my brain better.


Thanks, I was hoping someone would point out the mistakes. Since I can't edit my previous comment:

  frob = (obj, rest...) -> v for v of obj when blurgh(v, rest)
edit: parens dropped for noise reduction


A minor style point, but you can drop the parentheses here. They're only needed when you're assigning the result of the comprehension since = has a higher precedence. I go back and forth on whether it's better to remember this or to just put parens all the time.


The parentheses thing is the one thing that bugs me a bit about the CS syntax, but mostly when dealing with calling functions. I wouldn't mind omitting the parentheses around function arguments if I could be consistent about it. Seems like there are some cases where parentheses are necessary to make sure args go with the right function.

I'm wondering why I find this so annoying though. It's not like I complain about having to put parentheses in math to make sure stuff is evaluated with the precedence I want.


The way I think of it is "is this function call (including arguments) the last item on the line". If the answer is yes, you can drop the parens otherwise you have to keep them. E.g.

      foo bar baz 2    # is foo(bar(baz(2)))
      foo bar baz(), 2 # is foo(bar(baz(),2))
      foo bar().baz 2  # is foo(bar().baz(2))
In every case, the foo is the last item on the line. In the second there's an argument after the call to baz() so it's not the last thing on the line and needs parens. In the third, baz is being chained off bar so bar is not the last thing on the line and needs parens. In general I'd do all the parens except maybe the ones for foo in the second and third cases simply because it takes a minute to figure out where the calls get split when you re-read the code.

I tend to drop the call parens in situations the following:

    # DSLish things
    task 'foo', depends: ['bar']

    # Callback/lambda taking things
    xhr_get url, ->
         stop_animation()
That actually covers a fairly wide set of use cases for me since I tend to write DSLish/callback code but for things like `add(2,2)` I write in the parens regardless of position.


I'm personally of the opinion that prototype-based systems are superior to class-based systems in exactly the same way that gotos are superior to for loops.

Add to this the fact that JavaScript's prototype system isn't actually very flexible, and you're almost always better off to roll a class-based system on top of it.


> I can't shake the feeling that people that like CoffeeScript are those that don't "get" JavaScript

I disagree with this (though I agree with the rest of your post). The people that like CoffeeScript (and StratifiedJS and other projects like ObjectiveJ) are generally people that do get JavaScript really well. They just want to make it better.

The problem with CoffeeScript and the others is that they are not JavaScript. CoffeeScript is pretty straightforward in that it hardly even looks like JS and just compiles down to it, but others pretend to be JS but introduce new structures that make them all completely different languages (and do source transformation using JS in the browser).

If you don't know the transformations and you don't know JS very well, all these languages on top of JS will leave you stranded the second something goes wrong anywhere in the stack.

I'd like to see JS adopt some core structures for concurrency, namespaces and more CommonJS stuff instead of adding let, generators and comprehensions - which are nice, but mostly just fluff because you can do all those using the core language already and they're details nobody really cares about.


Chris Okasaki has some high praise for languages implementing indentation as part of the syntax http://okasaki.blogspot.com/2008/02/in-praise-of-mandatory-i...

Personally I think Coffeescript is a big step forward. A pity it will likely never gain enough momentum to see native implementations on the major browsers.


"Native implementations on the major browsers" will only harm coffeescript, since we'll never see rapid development and evolution of the language and maybe have to deal with the implementation incompatibility in different browsers.


> let go an embrace the prototypal object model

JavaScript itself doesn't embrace a prototypal model. When was the last time you cloned an object to create a new one in JS?

JavaScript's model is much closer to classes than prototypes. The only real significant difference is that unlike class systems, JavaScript allows inheriting both "methods" and "state" from its "class". Otherwise, the language works more or less like a class-based one.


    Sure, the name sucks, but that's hardly an issue.
Sure, as long as you already understand Javascript. Think of people who are learning, or middle managers that are hiring. It's a lot more of a thorn than you might think, because you're educated.


Is your only basis for feeling that people that like CoffeeScript don't "get" JavaScript the `class` syntax? If that's the case, it's a minor feature of CoffeeScript. I'd say the rest of the features it offers fall on the dynamic/functional side of things more than the strong+static typed/classical OOP side ( list comprehensions, splats, treating everything as an exression, etc.).


I agree with everything you are saying. Coffeescript really is for people who prefer a ruby/python syntax, and who just don't like javascript's syntax.

BEATUY IS IN THE EYE OF THE BEHOLDER people! Just because you find javascript 'ugly' and coffeescript 'beautiful' doesn't actually mean everyone agrees with you. I think Javascript is beautiful and I've been coding it for 14 years. I have no need to replace the syntax, or complicate my development tools, or make debugging any more complicated that it already is.

Coffeescript evangelists are like born-agains who try to convert every man woman or child to their newfound religion because their god is the true god. It's annoying really.


Who said everyone has to agree? If you don't like coffee script, don't use it.

It's that simple.


I couldn't agree more.

The biggest problem with CoffeeScript adoption is the administrative overhead required for novices to get it running. This means that most CoffeeScript projects are usually larger -- it just doesn't get used in small one-off things.

My company's product is a hosted CMS and we just tackled this problem (http://www.gethifi.com/blog/hosted-cms-coffeescript-support) by completely eliminating the workflow issue. You can use Coffee or JS and the system takes care of the rest for you.

I've found this to be a big help when working on smaller client sites. Often I just need to write a couple dozens lines of JS and it just isn't worth the hassle to do it in Coffee -- now it's gravy.


I started toying with CoffeeScript a while back for my own entertainment and found the administrative overhead was much less than I anticipated. I went from a clean slate to being up and running in like five minutes. Once I had node and CoffeeScript installed, it was just a single command-line to start a watch on my .coffee file and then I was back to "refresh browser window to see my changes" mode just like regular JS.


This is almost copy of CoffeeScript manual (plus some old jokes about Javascript)

Read original here, http://jashkenas.github.com/coffee-script/


I've done my fair share of web programming. But JavaScript (for me) has always been to add the flash, not to write the app. In the past couple of months, I dove into Backbone.js, Sammy.js, etc. and while my JavaScript worked, it wasn't "the JavaScript way".

When I found CoffeeScript, I was very happy. But I've been moving back to more JavaScript recently because I've spent hours looking through the generated JavaScript and learned quite a bit from it. I did the same with my C compiler and x86 Assembly :) It's nice to read what the experts think the final product should look like.

So write some CoffeeScript, compile it, and learn some JavaScript from it.


If you can't debug in CoffeeScript, you can't take it seriously. Even meta-CSS frameworks suffer from this problem when there's errors you have to back-track through a whole layer.


I love CS, but this article doesn't seem to have much useful content that isn't arleady in the CS docs: http://jashkenas.github.com/coffee-script/


Nope, but I read this article and then read the CS docs -- which I wouldn't have done if this article wasn't posted.


Out of curiosity:

What's with today's obsession over beautiful syntax? Shouldn't we strive for beautiful semantics, instead?


Absolutely, but the idea here is a bit different. JavaScript is a language that we're stuck with for the entire foreseeable future of the web, for better or for worse ... and CoffeeScript is a conscious attempt to try and work within that limitation. Unless you're willing to take the significant performance hit of running an interpreter on top of JavaScript, you have to stick fairly close to JavaScript semantics.

That said, we certainly try to improve upon JS semantics, where it's possible to do so without a performance hit. Things like auto-lexical scoping, bound functions, chained comparisons and, most importantly, "everything is an expression", are all examples of this.


Interesting; I wasn't aware that CoffeeScript makes some semantic improvements too. Everything is an expression is truly value-add.


No, you aren't trying to "improve JS semantics", you are trying to 'Rubyify' Javascript. You've created a language that is NOT javascript. Sorry, but no matter how hard you try to sell it as === javascript, it still will never be javascript. It's a Ruby syntax wrapped around javascript with some bells and whistles. It isn't a solution for javascript programmers, but it might be a solution for Ruby programmers.


It might also be a solution for programmers who don't tend to label themselves "LanguageX programmers".


are you trying to say that automatic lexical scoping and everything-is-an-expression are not improvements to javascript semantics? so what if they're "rubyfying" it?


In this case, the semantics were already decided: CoffeeScript was intended to map transparently to JavaScript. Each change to semantics would add complexity to that mapping.


Syntactic sugar is all CoffeeScript can ever be. Is pretty syntax better than common-use syntax?

(To be clear: I don't have a strong opinion. I'm curious what the community thinks the value proposition for CoffeeScript, HAML, etc is.)


Well it seems your assumption that "pretty" is purely a luxury, something that's nice to have but serves no practical purpose other than aesthetic satisfaction.

Personally I disagree.

I think a programming language is not like a car, at least not in that with a car whether it's pretty or not has no practical effect on the utility of the car.

You are using the computer language to express your own ideas, and to formulate your own constructs via it's syntax and semantics.

When the language's syntax and semantics are clunky, verbose, and full of line noise....those things become intermingled with your ideas and your semantics and it becomes difficult to separate the two.

I've been writing Javascript a long time, and what I like about CS is not only that it makes writing code easier by providing shortcuts for patterns I use constantly, but that the finished code more closely resembles the actual ideas I had when I wrote the code. With syntax and semantics that get out of the way you can focus more closely on your ideas and how to improve or fix them imho.


My perspective is a little more subtle than that. To clarify:

"Pretty" is great -- desirable, even. But if "pretty" comes at the cost of using immature tools that may slow me down, or at the cost of forcing my development team to learn a new syntax just because I believe it's "pretty" -- well, that's a harder value proposition.

That's what I'm trying to get at with all this. It sounds like, to you, the level of "pretty" in CoffeeScript outweighs the potential disadvantages -- which is great!

I do like the notion that CoffeeScript syntax gets out of the way; that it lays constructs and ideas bare in a way that JavaScript does not.


Pretty to me is the difference in being excited about writing code and feeling dead inside. Yes, a bit hyperbolic but I really don't like even looking at JS at this point. CS makes me more efficient for this reason and for the improved syntax. I feel the same way about Sass/Compass vs CSS, BTW.

How long do you expect it to take your team to learn the syntax? I would expect anyone with JS experience to have this [1] page open and be able to immediately start writing code and have it down in no time.

1. http://jashkenas.github.com/coffee-script/


I write javascript and I don't feel 'dead inside'. I love writing javascript, and I code all day every day. Just because you hate it doesn't mean it's bad.


This is all anecdotal, but learning CoffeeScript took me no more than a few hours, and I seem to be able to write CoffeeScript faster and with less errors than JavaScript. Obviously YMMV, but it's not just about "pretty".


That's a fair point, and there are a few things I would point out in no particular order:

The first is that CoffeeScript is ultimately a sort of dialect of Javascript. CS and JS can interact with eachother seamlessly, so as mentioned in the OP article there's no need to switch over to CS for everything and/or all at once.

Another important thing is that where possible CS tries to map relatively directly to JS, so for experienced JS developers they will recognize CS as a series of shortcuts which map to idioms they use constantly.

If you are familiar with JS, doing a few small projects in CS should get you pretty familiar with it.

CS is obviously somewhat immature, but I think it's reached the point where it can be considered for "serious work". I've found the tooling is pretty decent: coffee is slick with commands like --watch to recompile on changes, and coffee-mode for emacs is nice. There's also CS mode for vim, textmate, gedit, + more.

Honestly the main hurdle is potential debugging problems, but I haven't found that to be too difficult either. Being mindful of how CS transforms your code, and strategic debugging code make the process for me not much different from debugging regular JS.

So I'd say at this point I don't think CS presents hurdles which are terribly difficult to overcome.


> Is pretty syntax better than common-use syntax?

IMHO, in this instance, absolutely yes. I enjoy using CoffeeScript in a way I've never enjoyed JS. It's easier to write and easier to read. For example, compare:

    x = this.x;
    y = obj.map(function(z) {return z + x;});
with

    y = obj.map z => z + @x
I also find it of great benefit if I'm coding elsewhere in Ruby (for example, if I'm coming from some Ruby coding I'm prone to forgetting return statements in my JS at key moments).


Hm, to me the value proposition is this:

There are many, many interesting projects that I want to look at, read, potentially use or learn from.

Every little help for reading and understanding many open source projects faster is a huge value and a huge timesaver for me.

I think that clean syntax is just the better tool, like other people would probably prefer an IDE with integrated toolchain and dozens of tools that are modeled after the state of a programming system at some point in time.

Readable semantics behind a clean syntax are the more flexible toolchain in my eyes. It's like an integrated user interface. I can easily read and understand CS/Haml/Sass/Ruby/.. in my own files, in some libraries that i installed, in posts on blogs and on github ..


> Is pretty syntax better than common-use syntax?

What do you mean?


Javascript is understood by most developers these days. CoffeeScript is pretty.

(Edit: I don't think that "pretty" is a bad thing. I just... when is it the most important thing, or even high up on the priority list? Pretty isn't bad, but if it means learning an entirely new syntax and immature toolchain, its value for all but personal projects is unclear to me. I see that others value it differently, and I'm trying to understand why.)


For competent Javascript developers the learning curve to CoffeeScript is an afternoon tops, because it is Javascript. If you consider that, it essentially becomes a free lunch since now you can express your ideas more clearly than raw JS.


Interesting. To me, CoffeeScript is emphatically not JavaScript. There are new tools and, well, there's a new syntax. Semantically they may be (almost) equivalent -- but it strikes me as a far stretch to say they're the same, or that developers will treat them the same. I suppose I would feel similarly about HAML, too.


CoffeeScript syntax is close enough to Python or Ruby syntax that the syntax itself is "instantly readable" and "quickly writable" -- HAML on the other hand is altogether new syntax and much more 'innovative' on that front than I'd argue Coffee is.

I'd be really shocked if you showed a solid Javascript programmer who has written code in a scripting language like Perl, Python, or Ruby a chunk of CoffeeScript code and he/she couldn't easily infer what was going on just by intuition alone.


You say "pretty" like it's a bad thing...


It's unusual usage as well. Like referring to a keyboard that lets me type faster or a screen that's more readable as 'pretty'.


Javascript's semantics already suck and CoffeeScript is kind of stuck with that. Might as well focus on what they can make better.


Also, with a language like javascript, shouldn't we worry more about faster performance then beautiful syntax.


Absolutely, and CoffeeScript worries about your JS performance for you, when it can. In my personal experience, translating JS to Coffee tends to speed up the performance of the resulting script, due to the optimizations the CoffeeScript compiler adds.

To be specific, the main speedup I tend to get is this: If I'm working with JS, I'll tend to use a "forEach" function frequently, for looping over lists:

    list.forEach(function(item){ item.transform(); });
In CoffeeScript, you'd write it like this:

    item.transform() for item in list
... and instead of the slow "forEach" function, you get a much faster native "for" loop.


Does CoffeeScript include an optimizer/minifier? Google's "Closure" Compiler for JavaScript is able to inline functions and perform other interesting optimizations.


I've had trouble learning CoffeeScript due to the compiler not providing any help whatsoever when you make a mistake.

I was writing a web server that just wouldn't compile, looked the code over several times and eventually gave up and did it in javascript instead. Later found out that Gedit was displaying a tab that vim showed as just being a space. Never tested if that was the only problem or not.


Agreed. The compiler definitely isn't as helpful as it could be in giving information about errors. On the other hand, a lot of the errors it hits at compile-time are things you wouldn't have noticed until run-time if you were writing JavaScript.


I would love to see javascript turn into assembly language. Google has already done with with GWT with great improvements in productivity.

One question I had while reading this. Was there a technical reason why he didn't make a gem or toolkit in pure Ruby or Python that would then spit out Javascript?

I think this is closer to how GWT did it where you can write pure Java, and of course it then wouldn't require people to learn a new language.


The issue is Ruby/Python/Java's semantics don't map perfectly to JavaScript. As it says in the documentation, the golden rule of CoffeeScript is "It's just JavaScript".

For people who know JavaScript, it's not a new language-- just some syntactic sugar and a few bonus features.


I wonder if it's feasible to hack the javascript engines (v8, spidermonkey, ...) to support languages CoffeeScript? In case the answer is positive how come nobody's doing that?


I really wanted to like CoffeeScript but that it can't be metaprogrammed and serialized (easily) is a huge problem for a scripting language. I guess scripting was never the point of CoffeeScript, but a lot of what makes JavaScript so flexible is lost when you add a compile stage.


I'm struggling to think of something I can do in Javascript, but not CoffeeScript. Can you give an example?


I'm building a web-based IDE for Raphael in CS. My big pain point: when users define a function, JS Shell returns the JS version of the function. If the user types in a function name without calling it, they see the JS definition. Since one can't go from JS -> CS, I can't figure out a good way to keep JS away from the user.

http://fleetinbeing.net/raffi/ (type "spiral 30" to run a function defined in CS, then type "spiral" to see the definition in JS)


Because of whitespace and line break sensitivity you can't dynamically generate serialized CoffeeScript (unless delicately handled) because it won't compile.


Why would you even do that? You could just dynamically generate serialized JS and load it with CoffeeScript.



Ugh, there is nothing wrong with JavaScript, please let's all just forget that CoffeeScript even exists. Thank you.


I don't find an overly naive use of recursion that leads to an exponential time algorithm to be beautiful.


aka "How not to implement Fibonacci sequence"


Y U no cache the results?




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

Search: