Skip to content

Instantly share code, notes, and snippets.

@joshfrench
Created June 10, 2011 15:16
Show Gist options
  • Save joshfrench/1019035 to your computer and use it in GitHub Desktop.
Save joshfrench/1019035 to your computer and use it in GitHub Desktop.
NY Ruby Meetup/CoffeeScript notes

Hey folks,

We covered a lot of ground yesterday and I wanted to write up some notes on a few points that helped me get up the CoffeeScript learning curve.

List comprehensions

I spend most of my time in Ruby and ObjC and this is one of those language features I truly envy.

Let's say we have some DOM elements that need to be sortable via drag-and-drop. It'll work like the re-orderable queue on Netflix (if you still get DVDs mailed to you like a chump.)

<ul id="my-list" class="ui-sortable">
  <li><input type="text" name="Mad Max" value="0" /> Mad Max</li>
  <li><input type="text" name="Ghostbusters" value="1" /> Ghostbusters</li>
  <li><input type="text" name="Bridget Jones's Diary" value="2" /> Bridget Jones's Diary</li>
</ul>

This can be pretty simple if we use jQuery's sortable plugin. We just need to tell it what element we want sortable, and pass a callback to define what happens when things are re-ordered.

$('#my-list').sortable({	
  update: function(event, ui) {
    $('#my-list').find('input').each(function(index,input) {
      $(input).val(index);
    });
  }
});

This is short enough that CoffeeScript won't save us a ton of code, but in my mind the list comprehension is a lot tidier:

jQuery ->
  ($ '#my-list').sortable
    update: (event, ui) ->
      ($ input).val(index) for input, index in ($ '#my-list').find 'input'

There are a few things going on here worth discussing. First is the way I'm (not) using parens. Because CoffeeScript eliminates redundant punctuation, I can leave off the parens on method calls as long as it doesn't make anything ambiguous. I could have written ($ input).val index and ($ '#my-list').find('input') instead, but I think the idiomatic CoffeeScript style is to omit parens wherever possible. I find val(index) to be more readable here, but that's probably because I'm not used to reading list comprehensions.

Second, my jQuery selectors look a little funky: ($ '#my-list') instead of $('#my-list'). Because parens are optional, $ '#my-list' is perfectly valid. The outer parens make it clear that this is a single expression, though. That's one of the syntactical concepts that I really like about CoffeeScript -- your work units can be discrete expressions as well as functions. For me as a Rubyist, that's a very comfortable style.

Dashrockets vs Fatrockets

We touched on this but I'm not sure it was made clear. Here's the bestest click handler ever:

jQuery ->
  ($ 'a[rel=external]').click -> alert "Let's go to #{@href}!"

(If you're unfamiliar with CoffeeScript's @, it simply expands to "this.". Since @ is mostly a convenience for accessing member variables, it's supposed to remind you of Ruby's instance var sigil.)

When our click handler is executed, it's called on the <a> element and this.href will refer to the link's href attribute.

But if we use the fatrocket, we can do this:

jQuery ->
  @href = 'the mall'
  ($ 'a[rel=external]').click => alert "Let's go to #{@href}!"

Our handler is the same, but now we're using the fatrocket to define it. This binds the function to the local scope, where we've defined @href. (Remember: that's just shorthand for this.href.) So now our handler will always use the local variable. Fatrockets are good for making sure this doesn't change identities on you later.

String Interpolation

@harisamin and @snuggsi were debating string interpolation and whether it's really a gain over basic concatenation. My take is that operator overloading can be convenient, but you have to know all the rules. Consider Ruby's case statement, which overloads the === operator:

case foo
  when Fixnum then ...
  when /a string/ then ...

(This is for illustrative purposes only. If you have a method that doesn't even know what basic type to expect, there's a good chance you need to rethink something.) Other Ruby operators are similarly inconsistent, like *:

'1' * 5 #=> '11111'
5 * '1' #=> TypeError: String can't be coerced into Fixnum

I tend to take conveniences like this for granted, but violating the commutative property is what makes Pythonistas think we're a Manson Family of dangerously unwired hippies.

Given how sloppy JS is with its string and number types, I like to use interpolation for strings and reserve the + operator for numeric casts. Consistency breeds clarity, so when I see "Let's go to #{@href}!" and var i = +n they're like compiler hints for my brain.

Everything else

We didn't even mention the splat operator or deconstructive assignment and I won't get into them now. But there's plenty more sugar in CoffeeScript (SEE WHAT I DID THERE?) to check out. I found the CoffeeScript PeepCode and Trevor Burnham's CoffeeScript book both excellent resources, but there's no shortage of free material online.

@hamin
Copy link

hamin commented Jun 10, 2011

I LOVE string interpolation in Coffeescript. It really makes me happy :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment