550

I found this code in a RailsCast:

def tag_names
  @tag_names || tags.map(&:name).join(' ')
end

What does the (&:name) in map(&:name) mean?

user513951
  • 12,445
  • 7
  • 65
  • 82
collimarco
  • 34,231
  • 36
  • 108
  • 142

17 Answers17

547

It's shorthand for tags.map(&:name.to_proc).join(' ')

If foo is an object with a to_proc method, then you can pass it to a method as &foo, which will call foo.to_proc and use that as the method's block.

The Symbol#to_proc method was originally added by ActiveSupport but has been integrated into Ruby 1.8.7. This is its implementation:

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end
BoltClock
  • 700,868
  • 160
  • 1,392
  • 1,356
Josh Lee
  • 171,072
  • 38
  • 269
  • 275
  • 104
    tags.map(:name.to_proc) is itself a shorthand for tags.map { |tag| tag.name } – Simone Carletti Aug 01 '09 at 18:05
  • 6
    this isn't valid ruby code, you still need the `&`, i.e `tags.map(&:name.to_proc).join(' ')` – horseyguy Jun 25 '11 at 13:00
  • 5
    Symbol#to_proc is implemented in C, not in Ruby, but that's what it'd look like in Ruby. – Andrew Grimm Jul 04 '11 at 02:46
  • @banister I think you can write `tags.map(&:name).join(' ')` without the `to_proc` – Gerry Mar 08 '12 at 17:58
  • 1
    "A block may be associated with a method call using either a literal block .. or a parameter containing a reference to a Proc or Method object prefixed with an ampersand character." http://bit.ly/n8GpYw – Jared Beck May 16 '12 at 05:22
  • 5
    @AndrewGrimm it was first added in Ruby on Rails, using that code. It was then added as a native ruby feature in version 1.8.7. – Cameron Martin Feb 13 '13 at 19:13
  • 2
    Great answer! I think a link to show the entire Symbol implementation class would be useful. https://github.com/rubinius/rubinius/blob/master/kernel/common/symbol19.rb – Mogox Jun 20 '13 at 20:21
  • 4
    @SimoneCarletti - While `tags.map { |tag| tag.name }` is effectively what `tags.map(&:name.to_proc)` does, it is not exactly shorthand, per se. This is because procs can be converted to blocks, using the & operator, when they are passed to methods that use yield and thus require a block. (See the Ruby documentation [here](http://www.ruby-doc.org/core-2.0/doc/syntax/calling_methods_rdoc.html#label-Proc+to+Block+Conversion)). As Josh Lee showed in his post above, symbols can also be converted to procs and, from there, can then be converted to a block, which is necessary because map uses blocks. – jazzyfresh Aug 02 '13 at 21:46
  • 1
    I found a great article to explain more detailed ampersand operator in Ruby, hope it helps people. The "foo" followed "&" can be either a symbol or an Object. http://ablogaboutcode.com/2012/01/04/the-ampersand-operator-in-ruby/ – Jinzhao Huo Sep 04 '13 at 03:33
  • 2
    @JaredBeck had it right: the ampersand just tells ruby that _"this argument is the block, try your best to make it one if it ain't yet"_ – Tero Tilus Sep 05 '13 at 19:47
  • 1
    You should use `#__send__` instead of `#send` at it's safer. An object can override `send` for some reason (eg. sending emails), but if you do the same with `#__send__`, Ruby VM throws a warning. – Luca Guidi Oct 12 '15 at 10:27
  • it doesn't talk about how symbols are mapped/connected to actual methods. Symbol to proc sounds all good. But symbols are empty how do they become block of code. – Muhammad Umer Feb 28 '16 at 09:40
  • 1
    It's not just a shorthand, but also 20% faster and more idiomatic ruby code. – imtk Jun 17 '16 at 17:16
  • `If foo is an object with a to_proc method, then you can pass it to a method as &foo`. Please illustrate with an example, it's way too abstract for me. What is `&foo` language construct even called? Don't know what to google to make this more clear. – Marko Avlijaš Jun 09 '17 at 08:09
  • Wait -- `&:name` is shorthand for `&:name.to_proc`? If `&:name` unrolls to `&:name.to_proc`, then can't we apply the same "unroll" on that result, yielding `&:name.to_proc.to_proc`, ad infinitum? This doesn't make sense to me. – Jon Schneider May 26 '20 at 14:54
197

Another cool shorthand, unknown to many, is

array.each(&method(:foo))

which is a shorthand for

array.each { |element| foo(element) }

By calling method(:foo) we took a Method object from self that represents its foo method, and used the & to signify that it has a to_proc method that converts it into a Proc.

This is very useful when you want to do things point-free style. An example is to check if there is any string in an array that is equal to the string "foo". There is the conventional way:

["bar", "baz", "foo"].any? { |str| str == "foo" }

And there is the point-free way:

["bar", "baz", "foo"].any?(&"foo".method(:==))

The preferred way should be the most readable one.

Alan W. Smith
  • 24,647
  • 4
  • 70
  • 96
Gerry
  • 5,326
  • 1
  • 23
  • 33
84

It's equivalent to

def tag_names
  @tag_names || tags.map { |tag| tag.name }.join(' ')
end
Sophie Alpert
  • 139,698
  • 36
  • 220
  • 238
69
tags.map(&:name)

is The same as

tags.map{|tag| tag.name}

&:name just uses the symbol as the method name to be called.

Albert.Qing
  • 4,220
  • 4
  • 37
  • 49
51

While let us also note that ampersand #to_proc magic can work with any class, not just Symbol. Many Rubyists choose to define #to_proc on Array class:

class Array
  def to_proc
    proc { |receiver| receiver.send *self }
  end
end

# And then...

[ 'Hello', 'Goodbye' ].map &[ :+, ' world!' ]
#=> ["Hello world!", "Goodbye world!"]

Ampersand & works by sending to_proc message on its operand, which, in the above code, is of Array class. And since I defined #to_proc method on Array, the line becomes:

[ 'Hello', 'Goodbye' ].map { |receiver| receiver.send( :+, ' world!' ) }
Nisse Engström
  • 4,738
  • 23
  • 27
  • 42
Boris Stitnicky
  • 12,444
  • 5
  • 57
  • 74
41

It's shorthand for tags.map { |tag| tag.name }.join(' ')

Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
Oliver N.
  • 2,496
  • 19
  • 20
  • Nope, it's in Ruby 1.8.7 and above. – Chuck Aug 01 '09 at 17:41
  • Is it a simple idiom for map or Ruby always interpret the '&' in a particular way? – collimarco Aug 01 '09 at 17:43
  • 7
    @collimarco: As jleedev says in his answer, the unary `&` operator calls `to_proc` on its operand. So it's not specific to the map method, and in fact works on any method that takes a block and passes one or more arguments to the block. – Chuck Aug 01 '09 at 18:11
18

Two things are happening here, and it's important to understand both.

As described in other answers, the Symbol#to_proc method is being called.

But the reason to_proc is being called on the symbol is because it's being passed to map as a block argument. Placing & in front of an argument in a method call causes it to be passed this way. This is true for any Ruby method, not just map with symbols.

def some_method(*args, &block)
  puts "args: #{args.inspect}"
  puts "block: #{block.inspect}"
end

some_method(:whatever)
# args: [:whatever]
# block: nil

some_method(&:whatever)
# args: []
# block: #<Proc:0x007fd23d010da8>

some_method(&"whatever")
# TypeError: wrong argument type String (expected Proc)
# (String doesn't respond to #to_proc)

The Symbol gets converted to a Proc because it's passed in as a block. We can show this by trying to pass a proc to .map without the ampersand:

arr = %w(apple banana)
reverse_upcase = proc { |i| i.reverse.upcase }
reverse_upcase.is_a?(Proc)
=> true

arr.map(reverse_upcase)
# ArgumentError: wrong number of arguments (1 for 0)
# (map expects 0 positional arguments and one block argument)

arr.map(&reverse_upcase)
=> ["ELPPA", "ANANAB"]

Even though it doesn't need to be converted, the method won't know how to use it because it expects a block argument. Passing it with & gives .map the block it expects.

devpuppy
  • 822
  • 9
  • 8
15

Josh Lee's answer is almost correct except that the equivalent Ruby code should have been as follows.

class Symbol
  def to_proc
    Proc.new do |receiver|
      receiver.send self
    end
  end
end

not

class Symbol
  def to_proc
    Proc.new do |obj, *args|
      obj.send self, *args
    end
  end
end

With this code, when print [[1,'a'],[2,'b'],[3,'c']].map(&:first) is executed, Ruby splits the first input [1,'a'] into 1 and 'a' to give obj 1 and args* 'a' to cause an error as Fixnum object 1 does not have the method self (which is :first).


When [[1,'a'],[2,'b'],[3,'c']].map(&:first) is executed;

  1. :first is a Symbol object, so when &:first is given to a map method as a parameter, Symbol#to_proc is invoked.

  2. map sends call message to :first.to_proc with parameter [1,'a'], e.g., :first.to_proc.call([1,'a']) is executed.

  3. to_proc procedure in Symbol class sends a send message to an array object ([1,'a']) with parameter (:first), e.g., [1,'a'].send(:first) is executed.

  4. iterates over the rest of the elements in [[1,'a'],[2,'b'],[3,'c']] object.

This is the same as executing [[1,'a'],[2,'b'],[3,'c']].map(|e| e.first) expression.

prosseek
  • 182,215
  • 215
  • 566
  • 871
  • 2
    Josh Lee's answer is _absolutely_ correct, as you can see by thinking about `[1,2,3,4,5,6].inject(&:+)` - inject expects a lambda with two parameters (memo and item) and `:+.to_proc` delivers it - `Proc.new |obj, *args| { obj.send(self, *args) }` or `{ |m, o| m.+(o) }` – Uri Agassi May 20 '14 at 04:18
5

(&:name) is short for (&:name.to_proc) it is same as tags.map{ |t| t.name }.join(' ')

to_proc is actually implemented in C

Shamsul Haque
  • 2,441
  • 2
  • 18
  • 20
tessie
  • 964
  • 3
  • 14
  • 24
5

map(&:name) takes an enumerable object (tags in your case) and runs the name method for each element/tag, outputting each returned value from the method.

It is a shorthand for

array.map { |element| element.name }

which returns the array of element(tag) names

Sunda
  • 227
  • 3
  • 3
5

First, &:name is a shortcut for &:name.to_proc, where :name.to_proc returns a Proc (something that is similar, but not identical to a lambda) that when called with an object as (first) argument, calls the name method on that object.

Second, while & in def foo(&block) ... end converts a block passed to foo to a Proc, it does the opposite when applied to a Proc.

Thus, &:name.to_proc is a block that takes an object as argument and calls the name method on it, i. e. { |o| o.name }.

Christoph
  • 712
  • 1
  • 6
  • 17
4

Although we have great answers already, looking through a perspective of a beginner I'd like to add the additional information:

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

This means, that you are passing another method as parameter to the map function. (In reality you're passing a symbol that gets converted into a proc. But this isn't that important in this particular case).

What is important is that you have a method named name that will be used by the map method as an argument instead of the traditional block style.

Dmitry
  • 6,716
  • 14
  • 37
  • 39
Jonathan Duarte
  • 753
  • 5
  • 9
2

It basically execute the method call tag.name on each tags in the array.

It is a simplified ruby shorthand.

Olalekan Sogunle
  • 2,299
  • 1
  • 20
  • 26
2

There isn't a &: operator in Ruby. What you are seeing is the & operator applied to a :symbol.

In a method argument list, the & operator takes its operand, converts it to a Proc object if it isn't already (by calling to_proc on it) and passes it to the method as if a block had been used.

my_proc = Proc.new { puts "foo" }

my_method_call(&my_proc) # is identical to: my_method_call { puts "foo" }

MD Shahid Khan
  • 670
  • 4
  • 5
1

Here :name is the symbol which point to the method name of tag object. When we pass &:name to map, it will treat name as a proc object. For short, tags.map(&:name) acts as:

tags.map do |tag|
  tag.name
end
timlentse
  • 195
  • 2
  • 11
1

it means

array.each(&:to_sym.to_proc)
DDD
  • 471
  • 1
  • 5
  • 13
-1

It is same as below:

def tag_names
  if @tag_names
    @tag_names
  else
    tags.map{ |t| t.name }.join(' ')
end
Naveen Kumar
  • 2,570
  • 3
  • 20
  • 22