I wasn’t aware Ruby had &method syntax until I came across this PR in rubocop today.

In the previous post we saw how &:symbol works with iterators. Let’s disect &method this time.

&:method_name (notice the : after &) calls the method on the object while &method passes the object as an argument to the method.

def square(x)
  x * x
end

a = [1, 2, 3, 4]
a.map(&method(:square)) # => [1, 4, 9, 16]

How does this work?

Ruby methods are not real objects meaning we cannot call methods on them or pass them around directly. The Object class in Ruby has a method named method which returns the Method object corresponding to the method.

m = File.method(:read) # => #<Method: File(IO).read>
m.call("Gemfile") # => "source 'https://rubygems.org'\n\n....."

In the square example above we get the method object of square from self by calling method on self (self is implicit there). Then we are passing that method object to map but with &. This means Ruby will try to convert the Method object to Proc by calling to_proc. Something like this:

class Method
  def to_proc
    proc { |obj| self.call(obj) }
  end
end

a = [1,2,3,4]
def square(x); x * x; end
a.map(&method(:square)) # => [1, 4, 9, 16]

This code is for representation of how &method works, actual code is written in C and is much more sophisticated.

References:

  1. For full C implementation click toggle source here
  2. Rubocop PR for why method objects are sometimes bad