Search code examples
rubylambdayield

Why does yielding to lambda splat array arguments in Ruby?


In Ruby, calling a lambda with the wrong number of arguments results in an ArgumentError:

l = lambda { |a, b| p a: a, b: b }
l.call(1, 2) 
# {:a=>1, :b=>2}

l.call(1)
# ArgumentError: wrong number of arguments (given 1, expected 2)

Passing an array instead doesn't work either: (because an array is just a single object, right?)

l.call([3, 4])
# ArgumentError: wrong number of arguments (given 1, expected 2)

Unless I use a splat (*) to convert the array to an argument list, but I didn't.

But ... if I call the lambda implicitly via yield, something unexpected happens:

def yield_to
  yield(1, 2)
  yield([3, 4])
end

yield_to(&l)
# {:a=>1, :b=>2}
# {:a=>3, :b=>4}   <- array as argument list!?

What's even more confusing, a lambda derived via Method#to_proc does work as expected:

def m(a, b)
  p a: a, b: b
end

yield_to(&method(:m))
# {:a=>1, :b=>2}
# ArgumentError: wrong number of arguments (given 1, expected 2)

What's going on here?


Solution

  • I'm answering my own question here, because this is a known bug:

    https://bugs.ruby-lang.org/issues/12705

    And it was fixed in Ruby 2.4.1 (thanks @ndn)