Question

I noticed while learning Ruby that both of these uses of the each method work and produce the same output, and I was wondering how Ruby makes this happen (and how I can make it happen for my own functions):

my_array = [["hello","goodbye"],["picture","perfect"]]

my_array.each do |array|

  puts array[0] + " " + array[1]

end

my_array.each do |first, second|

  puts first + " " + second

end

My understanding is that when writing the definition of a method that accepts a code block, the yield method is utilized to pass arguments to the code block and call the block. But how can you utilize the yield method such that it passes different arguments depending on the provided code block? In the example case, it appears that the yield method passes the individual array elements when two parameters (i.e., first, second) are used within the block, and it passes the arrays themselves when one parameter is used within the block (i.e., array).

Was it helpful?

Solution

Neither each not yield are doing anything special here, that's just how block arguments work. Consider this simple example:

def f(x) yield x end

and now we can see what happens:

>> f([1,2]) { |a| puts a.inspect }
[1, 2]
>> f([1,2]) { |a, b| puts "#{a} - #{b}" }
1 - 2
>> f([1,2]) { |a, b, c| puts "#{a} - #{b} - #{c}" }
1 - 2 - 

You'll see similar destructing in assignments:

a, b = [1, 2]

You can also do it explicitly with a splat:

a, b = *[1, 2]

or like this:

def g(x) yield *x end
g([1, 2]) { |a, b| puts "#{a} - #{b}" }

Presumably the block knows what sorts of things it will be given so the block is well positioned to unpack the arguments. Note that the g function has to know that its argument is splatable (i.e. an array) but f doesn't. f nicely puts the "what sort of thing is x" logic together in the call to f, g buries half of the logic inside itself. One place where the difference becomes apparent is when you use Enumerable methods on a Hash:

{ :where => :is, :pancakes => :house? }.map { |k, v| ... }

Enumerable#map doesn't need to know that a Hash works in key/value two element arrays, it just passes things around and leaves it up everyone else to worry about the details.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top