An important difference between the proc method and the lambda method is how they handle the return statement. If the method is defined inside another method, the return statement in the inner method exits the innermost method, then the outer method continues to execute. The same applies to the definition of a lambda inside a lambda, a lambda inside a method, or a method inside a lambda. However, when proc is defined inside the method, the return statement will exit the proc, as well as the external (enclosing) method. Example:
def meditate puts "Adjusting posture…" p = Proc.new { puts "Ringing bell…"; return } p.call puts "Sitting still…" # This is not executed end meditate Output: Adjusting posture… Ringing bell…
Note that the last line of the method was not executed because the return statement inside the proc came out of the proc and include method.
If we define proc without an incoming (external) method and use the return statement, it will raise LocalJumpError.
p = Proc.new { puts "Ringing bell…"; return } p.call Output: Ringing bell… LocalJumpError: unexpected return
This is because when the return statement is reached inside proc, instead of returning from the context where it was called, it returns from the area on which it was defined (proc). In the following example, a LocalJumpError error occurs because proc is trying to return from the top-level environment where it was defined.
def meditate p puts "Adjusting posture…" p.call puts "Sitting still…" # This is not executed end p = Proc.new { puts "Ringing bell…"; return } meditate p Output: Adjusting posture… Ringing bell… LocalJumpError: unexpected return
It is generally not recommended to use the return statement in proc. Procs are usually passed between methods, and if the method by which proc was defined is already returned, it throws an exception. In the example below, we could simply remove the return statement. However, there are cases when we really need to return something. In the latter case, it is best to use lambda instead of proc. Later we will see that lambdas processes return statements differently as methods.
The following is another script that includes a return statement:
def zafu_factory # This method will return the following proc implicitly Proc.new { puts "Round black zafu"; return } end def meditate puts "Adjusting posture…" p = zafu_factory p.call puts "Sitting still…" # This is not executed end meditate Output: Adjusting posture… Round black zafu LocalJumpError: unexpected return
What just happened? The zafu_factory method was created and implicitly returned proc. Then proc was called by the meditation method, and when the return statement was received inside proc, it tried to return from the context on which it was defined (zafu_factory method). However, zafu_factory already returned proc, and the method can only return once every time it is called. In other words, the exception was thrown because the zafu_factory method already returned when proc was called and tried to return a second time.
Read more on this Procs and Lambdas blog: Ruby closure