1
votes

How does Ruby distinguish the codeblocks |n|'s in the functions yield case of "Kim" and the function call's case of "Eric"?

Apologies if this is painfully obvious - I really don't see how exactly the |n| variable in the codeblock with the function(arg) call effects the functions internal yield call?

def yield_name(name)
  puts "In the method! Let's yield..."
  yield("Kim")
  puts "... now in between the yields!"
  yield(name)
  puts "Block complete! Back in the method."
end

>>> yield_name("Eric") { |n| puts "My name is #{n}." }

In the method! Let's yield...
My name is Kim.
... now in between the yields!
My name is Eric.
Block complete! Back in the method.

As I understand the code block, it reads, "for each argument, put to screen "My name is #{that argument}". How does Ruby pass "Kim" into "that argument" so it prints "My name is Kim" instead of just "Kim"? Thank you.

---------------------- EDIT

Here's a less confusingly named example:

def double(parameter)
    yield parameter
    yield 7
end

When I invoke:

>>> double(3) { |n| puts "how? #{n * 2}" }

I get:

how? 6  #<-- relative to function call(arg)
how? 14 #<-- relative to internal functions yield call(arg)

So how does Ruby know to use yield 7 in the puts statement ?

2

2 Answers

2
votes

As I understand the code block, it reads, "for each argument, put to screen "My name is #{that argument}"

Nope. Literally, it reads "pass argument 'Eric' to method yield_name and also pass this block". The mere fact that you passed a block to method means nothing. The method can simply just not call it (also known as "yielding to block"). So you can't make any assumptions about number of block invocations or values of supplied parameters without knowing implementation of the method.

In this case, we do know the implementation

def yield_name(name)
  puts "In the method! Let's yield..."
  yield("Kim")
  puts "... now in between the yields!"
  yield(name)
  puts "Block complete! Back in the method."
end

Here we see that per each call, yield_name calls its block two times. First, with a static value ("Kim"). Second time, it simply relays its parameter name. If there were no yield statements here, the block you supplied would be completely ignored (and, therefore, nothing would be printed). But we do trigger the block two times and see two lines in the output.

1
votes

You could view the block as being conceptually similar to the method:

def my_block(n)
  puts "My name is #{n}."
end

And the yields as calling it:

my_block("Kim")
my_block(name)

In other words, the n is the argument of the block, and it gets its value from the yield, which triggers the block's execution every time a value is yielded.