Ruby Lambda vs Proc LocalJumpError

Ruby and StackOverflow newb, working through Ruby and stumbled upon my first main roadblock. I have a very difficult time wrapping my head around Procs and Lambdas. Here is the code I'm working with.

def procBuilder(message) Proc.new{ puts message; return} end def test puts "entering method" p = procBuilder("entering proc") p.call puts "exit method" end test 

By design, it is to throw a LocalJumpError, but I don't quite understand why. If I were to guess what it did, I would suggest that it would first print "proc input" when p = procBuilder ("proc input") was run, and then throw an error on p.call, since no line is passed p.call, but it’s clear that I am missing something critical that happens between these two lines. I also do not quite understand why this works with lambda and not with proc, but I believe that understanding the error will also solve this problem.

Thanks in advance for clarifying

+4
source share
2 answers

Here is the answer I gave to a related question. He talks a little about lambda vs proc and LocalJumpErrors.

In proc, return is a special piece of syntax that returns from the lexical domain of proc, not proc itself. Therefore, he is trying to return from procBuilder , which has already exited.

There are several ways to fix this:

  • Do not use return at all. Ruby will automatically return control for proc caller.
  • Change proc to lambda , which behaves as you expect. Lambdas acts like methods; procs act like blocks.

Regarding the error you expect, you should not do this. procBuilder returns a proc that includes the message variable. You do not need any arguments to the process itself.

Edit : Answer an additional question. Prok is closing. He “captured” the message variable (a local variable in procBuilder ) that was in scope when creating proc. Now proc can now navigate your program with a message variable hidden inside it, ready to be printed when you call it. The only problem is the return statement, which has the additional requirement that the lexical area is still "alive".

The reason for all this is that this behavior is really useful in blocks. In this case, this is not useful at all, so you should just use lambda , where return means something less crazy.

Great ruby ​​shutdown tutorial: http://innig.net/software/ruby/closures-in-ruby.rb

+4
source

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

0
source

Source: https://habr.com/ru/post/1381626/


All Articles