2
class MyClass
  extend Forwardable
  def_delegators :@broker, :add

  def subscribe_in_broker
    @subscribers.map(&method(:add))
  end
end

In this example @subscribers is a Hash and @broker.add takes two arguments: def broker(k,v).

This causes ArgumentError: wrong number of arguments (given 1, expected 2)

Is there a way to use Forwardable or a similar solution without this problem? How can I easily delegate an Array with 2 elements to a method which takes two arguments? What would be the equivalent of writing:

  def subscribe_in_broker
    @subscribers.map{|k,v| add(k,v) }
  end

but using delegation?

1 Answers1

1

It might seem like the block is receiving 2 arguments, but it is actually receiving only a single argument (a 2-element array). Ruby is interpreting the |x, y| as if it was |(x, y)|. The parentheses (which can be omitted here) destructure the single argument into its two pieces.

When you use a & with a method, it also only gets only 1 argument, and if you want to destructure it, you have to be explicit by using a set of parentheses around x and y:

def add((x,y))
end

To be clear, this is a single-argument method that expects the argument to be an array. For example, you call it like this: add([1, 2])

Note: this has nothing to do with delegation, just the fact that Ruby assumes you intend to destructure in one place, while not in another.

It is possible to yield more than one argument to a block (or a method turned into a proc with '&'), but that is not what map does.

It's not obvious to me why hash.map { |x,y| add(x, y) } is not adequate for your purposes. To work around that, you'd need to define your own map function that yields 2 arguments instead of 1, and that seems like overkill for this.

Nathan
  • 7,816
  • 8
  • 33
  • 44
  • 1
    Thanks for the helpful answer. Mine was rubbish (and I removed it to avoid confusing myself and others). – Lemon Cat Mar 20 '18 at 21:11