0

What is it called when you pass a block to a method in this way: .map(&:capitalize)?

Is it just syntactic sugar? Shorthand? Can you do anything else with it?

MrPizzaFace
  • 7,807
  • 15
  • 79
  • 123

1 Answers1

2

Every method in Ruby has a special "block" slot that isn't a normal argument. This is because passing precisely one block to a method is the most common use case and Ruby optimizes it¹. The & symbol is used to denote the passing of something specifically inside that slot.

def with_regular_argument(block)
  block.call
end

def with_block_argument(&block)
  block.call
end

with_regular_argument lambda { puts 'regular' }    # regular
with_block_argument { puts 'block argument' }      # block argument

The symbol can also be used when calling methods. That way, you can pass any object as the block, and to_proc will be called on it in order to coerce it to a Proc.

def to_proc
  proc { puts 'the main object was converted to a Proc!' }
end

with_block_argument &self    # the main object was converted to a Proc!

Note that the coercion would not have been performed had you invoked with_regular_argument:

begin
  with_regular_argument self
rescue => error
  puts error.message            # undefined method `call' for main:Object
end

The Symbol class implements to_proc. It basically works like this:

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

So, how does the following line work?

enumerable.map &:to_s
  1. We are passing :to_s in the special block slot. This is denoted by the &.
  2. The use of & calls to_proc on the symbol.
  3. to_proc returns a Proc that sends :to_s to the first argument.
  4. This Proc is then passed to the map method in the special block slot.
  5. Every element yielded becomes the receiver of the message.

It is pretty much equivalent to:

enumerable.map { |receiver| receiver.send :to_s }

¹ Yehuda Katz. Ruby is NOT a Callable Oriented Language (It’s Object Oriented). Blog post.

Matheus Moreira
  • 17,106
  • 3
  • 68
  • 107