true

Possible Duplicate:
What does map(&:name) mean in Ruby?

In Ruby, I know that if I do:

some_objects.each(&:foo)

It's the same as

some_objects.each { |obj| obj.foo }

That is, &:foo creates the block { |obj| obj.foo }, turns it into a Proc, and passes it to each. Why does this work? Is it just a Ruby special case, or is there reason why this works as it does?

upvote
  flag
This is also referred to as pretzel colon syntax. – anothermh

2 Answers 11

up vote 427 down vote accepted

Your question is wrong, so to speak. What's happening here isn't "ampersand and colon", it's "ampersand and object". The colon in this case is for the symbol. So, there's & and there's :foo.

The & calls to_proc on the object, and passes it as a block to the method. In Rails, to_proc is implemented on Symbol, so that these two calls are equivalent:

something {|i| i.foo }
something(&:foo)

Also, to_proc on Symbol is implemented in Ruby 1.8.7 and 1.9, so it is in fact a "ruby thing".

So, to sum up: & calls to_proc on the object and passes it as a block to the method, and Ruby implements to_proc on Symbol.

71 upvote
  flag
More precisely: the ampersand unpacks the Proc object so that it gets passed as if it was a literal block. Only if the object is not already a Proc object, does it call to_proc. – Jörg W Mittag
upvote
  flag
Symbol#to_proc is only native in Ruby > 1.9 – Steve Graham
6 upvote
  flag
@Steve: No, it's in 1.8.7 as well. p RUBY_VERSION # => "1.8.7" p ["a", "b", "c"].map(&:upcase) # => ["A", "B", "C"] – August Lilleaas
upvote
  flag
you're right. it's not in ruby-doc.org/core/classes/Symbol.html for some weird reason though?! :S – Steve Graham
1 upvote
  flag
1 upvote
  flag
Thanks, that makes sense. Good to know that it's in Ruby 1.8.7 and 1.9. – Allan Grant
upvote
  flag
thanks august. do you know what version of ruby the default docs cover? i.e. /core not /core-1.8.7, /core-1.9. i always thought it was the latest release of 1.8? the way it is is not very helpful! – Steve Graham
upvote
  flag
It is explained on ruby-doc.org. /core is 1.8.6, then there's /core-1.8.7/ and /ruby-1-9/ (yay for no convention). – August Lilleaas
upvote
  flag
@August: Did you mean "ruby-doc.org/core is for 1.8.6"? in your first comment? – Andrew Grimm
upvote
  flag
@Andrew: yes, I did – August Lilleaas
1 upvote
  flag
Thanks. This is the first time I've actually understood what &: was doing, despite using the convention for years. – David Hempy
upvote
  flag
Let's say foo has an attribute name, is it possible to apply the ampersand on the foo.name? e.g. in pseudo-code example: something(&:foo.name). – null

There's nothing special about the combination of the ampersand and the symbol. Here's an example that (ab)uses the regex:

class Regexp
  def to_proc
    ->(str) { self =~ str ; $1 }
  end
end
%w(station nation information).map &/(.*)ion/

=> ["stat", "nat", "informat"]

Or integers.

class Integer
  def to_proc
    ->(arr) { arr[self] }
  end
end

arr = [[*3..7],[*14..27],[*?a..?z]]
arr.map &4
=> [7, 18, "e"]

Who needs arr.map(&:fifth) when you have arr.map &4?

3 upvote
  flag
Liked this example better than answer marked correct – Donato

Not the answer you're looking for? Browse other questions tagged or ask your own question.