In Ruby 1.8, there are subtle differences between proc/lambda on the one hand, and Proc.new
on the other.
- What are those differences?
- Can you give guidelines on how to decide which one to choose?
- In Ruby 1.9, proc and lambda are different. What's the deal?
Closures in Ruby is a good overview for how blocks, lambda and proc work in Ruby, with Ruby.
To provide further clarification:
Joey says that the return behavior of
Proc.new
is surprising. However when you consider that Proc.new behaves like a block this is not surprising as that is exactly how blocks behave. lambas on the other hand behave more like methods.This actually explains why Procs are flexible when it comes to arity (number of arguments) whereas lambdas are not. Blocks don't require all their arguments to be provided but methods do (unless a default is provided). While providing lambda argument default is not an option in Ruby 1.8, it is now supported in Ruby 1.9 with the alternative lambda syntax (as noted by webmat):
And Michiel de Mare (the OP) is incorrect about the Procs and lambda behaving the same with arity in Ruby 1.9. I have verified that they still maintain the behavior from 1.8 as specified above.
break
statements don't actually make much sense in either Procs or lambdas. In Procs, the break would return you from Proc.new which has already been completed. And it doesn't make any sense to break from a lambda since it's essentially a method, and you would never break from the top level of a method.next
,redo
, andraise
behave the same in both Procs and lambdas. Whereasretry
is not allowed in either and will raise an exception.And finally, the
proc
method should never be used as it is inconsistent and has unexpected behavior. In Ruby 1.8 it actually returns a lambda! In Ruby 1.9 this has been fixed and it returns a Proc. If you want to create a Proc, stick withProc.new
.For more information, I highly recommend O'Reilly's The Ruby Programming Language which is my source for most of this information.
Proc is older, but the semantics of return are highly counterintuitive to me (at least when I was learning the language) because:
Lambda is functionally safer and easier to reason about - I always use it instead of proc.
I didn't notice any comments on the third method in the queston, "proc" which is deprecated, but handled differently in 1.8 and 1.9.
Here's a fairly verbose example that makes it easy to see the differences between the three similar calls:
Understanding Ruby Blocks, Procs and Lambdas by Robert Sosinski clearly explains these programming concepts and reinforces the explanations with example code. Method objects are related and covered as well.
It's worth emphasizing that
return
in a proc returns from the lexically enclosing method, i.e. the method where the proc was created, not the method that called the proc. This is a consequence of the closure property of procs. So the following code outputs nothing:Although the proc executes in
foobar
, it was created infoo
and so thereturn
exitsfoo
, not justfoobar
. As Charles Caldwell wrote above, it has a GOTO feel to it. In my opinion,return
is fine in a block that is executed in its lexical context, but is much less intuitive when used in a proc that is executed in a different context.