def foo f = Proc.new { return "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end def bar b = Proc.new { "return from bar from inside proc" } b.call # control leaves bar here return "return from bar" end puts foo # prints "return from foo from inside proc" puts bar # prints "return from bar"
I thought the return
keyword was optional in Ruby and that you are always return
ing whether you request it or not. Given that, I find it surprising that foo
and bar
have different output determined by the fact that foo
contains an explicit return
in Proc f
.
Does anyone know why this is the case?
There are only two main differences. First, a lambda checks the number of arguments passed to it, while a proc does not. This means that a lambda will throw an error if you pass it the wrong number of arguments, whereas a proc will ignore unexpected arguments and assign nil to any that are missing.
When using parameters prefixed with ampersands, passing a block to a method results in a proc in the method's context. Procs behave like blocks, but they can be stored in a variable. Lambdas are procs that behave like methods, meaning they enforce arity and return as methods instead of in their parent scope.
Procs are objects, blocks are notA proc (notice the lowercase p) is an instance of the Proc class. This lets us call methods on it and assign it to variables. Procs can also return themselves. In contrast, a block is just part of the syntax of a method call.
A Proc object is an encapsulation of a block of code, which can be stored in a local variable, passed to a method or another Proc, and can be called. Proc is an essential concept in Ruby and a core of its functional programming features.
Ruby has three constructs:
{
... }
or do
... end
.Proc
object created by Proc.new
or proc
.Proc
created by lambda
(or proc
in Ruby 1.8).Ruby has three keywords that return from something:
return
terminates the method or lambda it is in.next
terminates the block, proc, or lambda it is in.break
terminates the method that yielded to the block or invoked the proc or lambda it is in.In lambdas, return
behaves like next
, for whatever reason. next
and break
are named the way they are because they are most commonly used with methods like each
, where terminating the block will cause the iteration to resume with the next element of the collection, and terminating each
will cause you to break out of the loop.
return
inside the definition of foo
, you will return from foo
, even if it is inside a block or a proc. To return from a block, you can use the next
keyword instead. def foo f = Proc.new { next "return from foo from inside proc" } f.call # control leaves foo here return "return from foo" end puts foo # prints "return from foo"
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With