Reputation: 621
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.
Upvotes: 11
Views: 10822
Reputation: 1889
I am coming from a C background and the way I would explain it is when you call a function you set a return instruction number and a register which will store the returned value. In case of proc and block the return instruction is not set because they are inlined or called in the same scope but they can still give back a returned value because these are independent functionalities. So, without a return instruction being set proc/block are giving us a LocalJumpError while if we just want to give a value back that is fine.
Upvotes: 1
Reputation: 22007
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.
Upvotes: 9