This is CoffeeScript
robots.thoughtbot.com
robots.thoughtbot.com
Somewhere along the way, I came across Paul Grahams essay "Succinctness is Power" ( http://www.paulgraham.com/power.html ), and I thought about how my productivity could be increased if I had access to a language that offered me the ability to do more with less. That was when I decided to revisit Coffeescript.
For my first task, I decided to rewrite some of my simpler javascript code into Coffeescript just to get a feel for it. Initially, the things that had initially repulsed me were somewhat irritating:
* The lack of parenthesis and brackets - I doubted that it would be possible to maintain code readability without them
* The reliance on indentation
* The overall "strangeness" of the appearance of coffeescript code (to someone with a predominantly java background)
Here's the thing though. All of those objections are only surface deep. Once I actually started to code in Coffeescript, I found that I became completely comfortable with the syntax. As a matter of fact, I don't think that I could ever go back to conventional javascript again. Especially because I would lose (among other things):
* An elegant syntax for writing classes using javascript
* List comprehensions
* Elegant string interpolation (it's the little things that count)
It is easy to be skeptical about coffeescript if you natural lean away from things that are surrounded by hype, but, take it from me, coffeescript really is an extremely valuable tool that no web developer should be without. It is more than just a way to write pretty javascript. It is a powerful, flexible, and elegant language in its own right. Don't be turned off by its syntax, give it a try today!
Going through the Table of Contents on http://jashkenas.github.com/coffee-script/ I've picked out the features of CoffeeScript that make it a different beast than just a JavaScript without warts.
* Lexical Scoping and Variable Safety * Conditional Assignment * Splats * Comprehensions * Everything is an Expression (&implicit return) * The Existential Operator * Classes, Inheritance, and Super * Destructuring Assignment * Function binding * Chained Comparisons * Extended Regular Expressions
This is beyond a simple sweetener for your JavaScript code. Yes, you could write your JavaScript like you write your CoffeeScript, but you wouldn't.
Try this little jewel in Try CoffeeScript and you'll see what I mean:
[open, contents..., end] = "<impossible>".split "" alert contents.join ""
I suppose if you're using it to make skirting the "Law of Demeter" and thats something you don't want to do it could seem like something bad.
But I'll take "foo?.bar()" over "foo.bar() if foo" gladly.
I found myself trying to decide whether or not to use it the other day and decided for now it was too clever. So I guess the jury is out in my own head, maybe not in anyone else's.
That's easy enough to remember, though.
I about CoffeeScript as JSLint + Syntactic Sugar. Both of which mean you need less heroics to get Javascript right.
I wouldn't expect you to believe me until you've used CoffeeScript for a little while, but I think you're definitely wrong about this. CoffeeScript simply has better syntax than plain js in every way, and any js developer will be more productive using it. The only drawbacks are dealing with file conversions and debugging, but these are something like a 10% penalty at worst on top of a 100%+ productivity boost. It's not just an aesthetic preference thing. CoffeeScript is a much better language and is pretty much guaranteed to save you time and mental effort.
That's a pretty bold claim. Have any examples to back it up? Most of what I've seen of coffescript (note: I haven't looked hard) seems to be relatively similar syntax with fewer characters or fixing JS gotchas that many developers are familiar with.
Both of these are useful things, but they don't make a 100%+ productivity boost in my mind.
value = switch value
when 1 then one
else whatever
Closures. do (value) ->
#value is wrapped in a closure
The 'class' macro.And that's just off the top of my head. Yes, it compiles to JavaScript. You could write all this by hand. It would be a waste of your time-- CS writes safe, efficient, readable code faster and better than you do, every time.
Look harder.
I understand that puts me in a small boat. In my opinion, people shouldn't use the class macro without knowing what it really does. Actually I'd extend that to say people shouldn't use CoffeeScript at all without an understanding of the JavaScript it compiles to, just as you shouldn't use C without an understanding of the assembly it compiles to... But that's probably wishful thinking. It wouldn't be an improvement for those people to write assembly (or raw JS) instead.
It really is true that having a compiler make it impossible to screw up your scope saves you from a lot of mistakes. This feature is probably the thing I wish we had put in Objective-J most. It's also really nice to have a syntax for classes.
Do you not agree that writing 100 lines of code instead of 1000 lines saves time, when writing it but perhaps most importantly when reading it and developing it further?
I'm not saying CoffeeScript cuts down the number of lines of code by a factor of ten, but, depending on what you do with it, often by 50% or more.
Making it about "keystrokes" is a bit disingenuous, it's about cruft (aka "keystrokes") but it's also about lines of code, imho.
Simple iteration over the key/value pairs of a javascript object requires that I remember to check hasOwnProperty at the right times. Soaking up nulls is a pain. Dealing with args kind of sucks. There's quite a bit more.
It's less valuable that these things can be done with shorter character sequences, and more valuable that I don't have to think about them nearly as much.
item = new Item title: "Awesome", id: 2
Less isn't always better. I like the parens, at least if there's more than one argument. item = new Item(title: "Awesome", id: 2)
It's much easier for me to glance at this and know what's going on.It only gets worse with nested function calls:
item = new Item title: new Title "Awesome", id: 2
The syntax isn't ambiguous, but that doesn't mean it's easy for humans to parse.item = (new Item title: "Awesome", id: 2)
Coffeescript has that ruby-esque intuitiveness. A lot of time I refactor code on a gut feeling that it'll work, coffee -p, yup it does ... 9 out of 10 times. closure, is, in, of, soaking null references lets you focus more on your code rather than on patterns, handling corner cases and avoiding mistakes; and I just discovered the fat arrow thanks to this post. (Yup, the documentation is all there on the homepage but, agree or not, learning is incremental and involves mistakes and serendipity.)
... which does indeed miss the point -- the side-by-side comparison on the homepage is not to show you what the equivalent handwritten JavaScript would be -- it's the actual JS output compiled from the CoffeeScript on the left. More of a "nothing up my sleeves" and no bullshit maneuver.
In a perfect world, CoffeeScript would compile into the JavaScript you would have written in the first place -- but that's quite a tall order.
Dear sir,
I'm jumping on my bed right now out of ecstasy, for my unworthy comment has garnered a reception, from a noble soul like yours.
You just made by day. In fact, you do it through the means of coffeescript everyday. Thank you for coffeescript, kind sir.
Hats off.
A broke, insecure, forever alone developer.
</public_display_of_affection>
I mean, look at what Hello World in C is, compared to Hello World in Haskell!
http://pastebin.com/sePpUJ1J (Haskell source)
http://pastebin.com/seqAy4VD (C, generated from the Haskell above)
Clearly C is unreadable garbage! (It's less expressive than Haskell, for sure, but showing generated output makes it look far worse)
This makes CoffeeScript fit really well into the JS-centric environment that has grown up around tools like JQuery and backbone. It's also very easy to debug in the browser compared to the environments that are targeting JS as an object code.
Personally, I don't think of CoffeeScript as a fully independent language but, rather, as a way to write JS which is cleaner, more reliable, and more fun.
If you really want to turn JS into a black box (and there are some good arguments for that), GWT or ClojureScript might be better choices for you.
(I've been writing a bunch of CoffeeScript lately and loving it. I'm very anxious to try my hand at ClojureScript also. GWT has always seemed very unwieldy to me.)
It's always fun to see a "CoffeeScript rocks" article like this explode on HN and Twitter. But it's even better to see stuff that people are building in CoffeeScript. The language has reached the point where it's gaining real traction in production settings, and not just among the beautiful code addicts at 37signals. There was a YC job posting about a week ago for a "CoffeeScript drinking frontend engineer" (http://news.ycombinator.com/item?id=2877677); they're also using CoffeeScript for a Node.js server, and even for MongoDB queries. I'm really excited to see that become a more common occurrence.
Honestly, CoffeeScript is neat but it's not much of an improvement over JS. It's just as ugly and unreadable. It's only an improvement if you're counting characters.
I don't find CoffeeScript any less ugly or readable than JS. It seems incredibly redundent.
Why make that point? It has absolutely no intellectual content.
You don't find it easier to read. Fair enough. I think a lot of people do. I personally found it much easier to write structured code in Coffeescript than in Javascript straight.
class ItemView extends Backbone.View
render: ->
@options.items.each(@renderItem)
renderItem: (item) =>
@el.append item.get("title")
It doesn't make sense because there are magic variables appearing out of nowhere - @options, @el, append -- what are these? I'd have to study the resulting JavaScript to understand what it's really going to do.(This also might be a bad example, but it was based off of code I wrote)
In other words, C is somewhat cross platform, and much higher level than assembler. Ruby does way more out of the box than C does.
Coffeescript seems to mostly just be a modified JavaScript syntax, although I have to admit I haven't looked at it that closely.
The abridged syntax is just gravy.
Once.
And then you could use shorter, more convenient syntax for the rest of your life. Worth it?
`this.options` is the options object that was passed when the View was created, and `this.el` is the default DOM element that wraps the View. For more info, see:
function ItemView() {
this.render = function() {
this.options.items.each(this.renderItem.bind(this));
}
this.renderItem = function(item) {
this.el.append(item.get("title"))
}
}
In this example, I don't see any significant difference as far as readability goes, to be honest. I will note, in case it is not entirely clear, that the use of Backbone in the example is unrelated to CoffeeScript.But I haven't been able to bring it into my main rails app since I'd like to have all of my JS consistently in coffeescript. I don't like having both JS/CS, just like I don't like having HAML/ERB mixed together.
It would be a big project migrating it over and not as simple as HAMLizing a project.
Maybe one day I'll do it, or wait for a future rails projects.
Although I did have a few problems with some more complex code, it seemed to do the trick for more straightforward javascript. You'll lose your comments, but it's worth checking out.
CS does have some rough spots that feels at odd with rest of the language but, overall, it brings clarity and convenience at minimal cost.
self= @
at the top of functions. The fat arrow for binding 'this' certainly helps but when you have to be really careful when writing code that nests several functions.Also, would be nice if the for-loop had a way to automatically wrap the block in a function without having to write
for(var x in lst) do (x) ->
whatever(x)Also, sometimes I do
$.each lst, (i, item) ->
whatever x
because I always use jQuery in my projects.Because of how jQuery binds the queried element to this, and the fat arrow overrides this, there doesn't seem to be another way to access both your class and the jQuery element in the same function.
for instance:
class ButtonLogger
constructor: ->
@clickedButtons = []
$(document).ready => @init()
init: ->
self = @
$('button').click ->
$button = $(@)
self.clickedButtons.push $button.attr 'id' $('button').click (e) =>
@clickedButtons.push $(e.target).attr 'id'The fat arrow is a great helper and saves a lot of work in various situations....obviously it doesn't cover all situations...but in the situations it doen't cover I'm not sure what I'd expect the language to do.
Could you give an example of what you imagine the feature to be?
I'm just not sure if something as simple and easy as
that = @
needs improvement. Anything beyond what that and => covers, to me seems like something a library should handle...and CS makes that very easy.For you second one, what about
do ( -> whatever x ) for x in foobar
One of the things I like about CS is that it is very conservative about not adding helpers for every little thing you can think of. It chooses a few very powerful and fundamental building blocks, and let's you use those to build up yourself.I can respect some people wanting more though.
do () for x in foobar
syntax. Thanks."""
( do (x) -> whatever x ) for x in foobar
or foo = (x) -> whatever x
foo x for x in foobar
or for x in foobar
do (x) -> whatever x
I find all of these pretty readable and easy. The former in simple cases like "whatever x", and the latter two when you are doing more than just "whatever x".I think it's important to distinguish cases like this and that the syntax is clean enough without adding some helper that makes what's going on implicit
"""
In the section where it says:
""" do ( -> whatever x ) for x in foobar """
I've written thousands of lines of JavaScript, and a coupla hundred of CoffeeScript. CS is a usable, rather polished JS overlay, but I only understand it in terms of JS. In any case, I know which will be around longer.
>This is such nonsense. Why did we put up with this? In CoffeeScript, you can write:
>html = "<option value='#{@id}'>#{@get("title")}</option>"
I have to say, the first one is much easier for me to read and understand.
http://www.linuxjournaldigital.com/linuxjournal/201109/?pg=3...
In particular, Ruby and Python both require more typing. At their most concise:
Ruby: -> {}
Python: lambda: JavaScript: fu<tab><shift-)>
function(){
<cursor>
}
Python: la<tab>:
The remaining characters should be filled in by most modern IDE / IDE plugins. a [1] = 2