Ruby and StackOverflow newb here working my way through Ruby and ran into my first major roadblock. I'm having a really hard 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, this is to throw a LocalJumpError, but I don't rightly understand why. If I had to guess what this did, I would guess it would initially print "entering proc" upon p = procBuilder("entering proc") running then throw an error on p.call as there is no string being passed by p.call, but clearly I'm missing something critical that is occurring between those 2 lines. I also don't completely understand why this works with a lambda rather than a proc but I imagine understanding the error will resolve that issue as well.
Thanks in advance for the clarification
Here's an answer I gave to a related question. It talks a bit about lambda vs proc and LocalJumpErrors.
In a proc, return
is a special piece of syntax that returns from the lexical scope of the proc, not the proc itself. So it's trying to return out of procBuilder
, which has already exited.
There are a couple ways to fix this:
return
at all. Ruby will return control to proc's caller all on its own.proc
to lambda
, which behaves the way you expect. Lambdas act like methods; procs act like blocks.As for the error you're expecting, you shouldn't get that. procBuilder
returns a proc that encloses the message variable. You don't need any arguments to the proc itself.
Edit: answering your additional question. The proc is a closure. It has "captured" the message variable (a local variable in procBuilder
), which was in scope when the proc was created. The proc now can wander through your program with the message variable hidden inside of it, ready to be printed when you call it. The only trouble is the return statement, which has the additional requirement that it the lexical scope still be "live".
The reason for all this is that this behavior is really helpful in blocks. In this case, it's not helpful at all, so you should just use a lambda
, where return means something less insane.
A really great tutorial on closures in ruby: http://innig.net/software/ruby/closures-in-ruby.rb