19

What does &method(:function) mean? For example, I have this line:

res = integrate(0, 1, a, &method(:function))
pjs
  • 18,696
  • 4
  • 27
  • 56
RubyBeginner
  • 303
  • 1
  • 8

2 Answers2

18

Say we have a method

def add_one(num)
  num + 1
end

and an array of strings

arr = ["1", "2"]

We want to map the list of strings to their corresponding outputs from add_one.

To start out we can call

nums = arr.map(&:to_i)

This is the same thing as

nums = arr.map do |str|
  str.to_i
end

You can see What does map(&:name) mean in Ruby? for more info on this.

However, it won't work to call:

nums.map(&:add_one)

Why? Because numbers have no built in method add_one. So you'll get a NoMethodError.

So, rather than providing just a method name :add_one you can pass an bound method method(:add_one):

nums.map(&method(:add_one))

Now, rather than each num being used as the receiver for the add_one method, they will be used as arguments. So, it's essentially the same as:

nums.map do |num|
  add_one(num)
end

To give another example, compare the following:

[1].map(&:puts)
# this is the same as [1].map { |num| num.puts }
# it raises NoMethodError

[1].map(&method(:puts))
# this is the same as [1].map { |num| puts num }
# it prints 1 successfully
max pleaner
  • 26,189
  • 9
  • 66
  • 118
  • Nitpick: `Object#method` returns a *bound* `Method`, not an `UnboundMethod`. The method is *bound* to a receiver because you are calling it on an instance and it thus knows what `self` is, whereas `Module#instance_method` returns an `UnboundMethod` because it can't know what instance it will be going to be used with. – Jörg W Mittag Jan 11 '20 at 19:59
  • @JörgWMittag Ok thanks for the correction, you are right I must have been mixing it up with `.instance_method` because I was just going by (flawed) memory – max pleaner Jan 11 '20 at 20:26
11

method(:function) is a message send (sometimes called a method call) to the implicit receiver (i.e. self). It is sending the message method to the implicit receiver (i.e. self), passing :function as the sole argument.

:function is a Symbol literal, i.e. it is the literal notation of a Symbol. Symbol is a data type representing "the name of something".

The unary prefix ampersand & operator "unrolls" a Proc into a block. I.e. it allows you to pass a Proc where a block is expected. If the object is not already a Proc, it will be sent the to_proc message allowing it to convert itself into a Proc. (The operator is only legal in an argument list and only for the last argument. It is the dual of the & sigil in a parameter list, which "rolls" a block into a Proc object.)

Proc is a datatype representing executable code. It is Ruby's core library class for first-class subroutines.

So, what this does, is call the method method on self with :function as the argument, call to_proc on the return value, "unroll" the resulting Proc object into a block and pass that block to the call to integrate as if you had written something like

res = integrate(0, 1, a) do
  # something
end

The method method here is most likely, the Object#method method, which returns a bound Method object.

So, all in all, this is somewhat equivalent to

res = integrate(0, 1, a) do |*args, &block|
  function(*args, &block)
end

But expressed in what is commonly called pointfree style.

Jörg W Mittag
  • 363,080
  • 75
  • 446
  • 653