I am having a lot of trouble understanding how return
works in blocks, procs, and lambdas.
For instance, in the following case, why does batman_ironman_proc
work, while batman_yield
throw an error?
def batman_ironman_proc
victor = Proc.new { return "Batman will win!" }
victor.call
"Iron Man will win!"
end
def batman_yield
yield
"Iron man will win!"
end
victor = Proc.new { return "Batman will win!" }
puts batman_ironman_proc
#batman_yield(&victor) === This code throws an error.
As one answer in the linked question shows:
The
return
keyword always returns from the method or lambda in the current context. In blocks, it will return from the method in which the closure was defined. It cannot be made to return from the calling method or lambda.
Your first example was successful because you defined victor
in the same function you wanted to return from, so a return
was legal in that context. In your second example, victor
was defined in the top-level. The effect of that return
, then, would not be to return from batman_yield
(the calling method), but [if it were valid] to return from the top-level itself (where the Proc
was defined).
Clarification: while you can access the return value of a block (i.e. "The value of the last expression evaluated in the block is passed back to the method as the value of the yield" - as per your comment), you can't use the return
keyword, for the reason stated above. Example:
def batman_yield
value = yield
return value
"Iron man will win!"
end
victor = Proc.new { return "Batman will win!" }
victor2 = Proc.new { "Batman will win!" }
#batman_yield(&victor) === This code throws an error.
puts batman_yield(&victor2) # This code works fine.