If you pass the wrong number of arguments to a lambda, it will raise an exception, just like a regular method.
Lambdas vs Procs
Procs are a very similar concept…
One of the differences is how you create them.
Example:
my_proc = Proc.new { |x| puts x }
There is no dedicated Lambda class. A lambda is just a special Proc object. If you take a look at the instance methods from Proc, you will notice there is a lambda? method.
Now:
A proc behaves differently than a lambda, specially when it comes to arguments:
t = Proc.new { |x,y| puts "I don't care about arguments!" }
t.call
# "I don't care about arguments!"
Another difference between procs & lambdas is how they react to a return statement.
A lambda will return normally, like a regular method.
But a proc will try to return from the current context.
Here’s what I mean:
If you run the following code, you will notice how the proc raises a LocalJumpError exception.
The reason is that you can’t return from the top-level context.
Try this:
# Should work
my_lambda = -> { return 1 }
puts "Lambda result: #{my_lambda.call}"
# Should raise exception
my_proc = Proc.new { return 1 }
puts "Proc result: #{my_proc.call}"
If the proc was inside a method, then calling return would be equivalent to returning from that method.
This is demonstrated in the following example.
def call_proc
puts "Before proc"
my_proc = Proc.new { return 2 }
my_proc.call
puts "After proc"
end
p call_proc
# Prints "Before proc" but not "After proc"
Here is a summary of how procs and lambdas are different:
Lambdas are defined with -> {} and procs with Proc.new {}.
Procs return from the current method, while lambdas return from the lambda itself.
Procs don’t care about the correct number of arguments, while lambdas will raise an exception.
Taking a look at this list, we can see that lambdas are a lot closer to a regular method than procs are.
Closures
Ruby procs & lambdas also have another special attribute. When you create a Ruby proc, it captures the current execution scope with it.
This concept, which is sometimes called closure, means that a proc will carry with it values like local variables and methods from the context where it was defined.
They don’t carry the actual values, but a reference to them, so if the variables change after the proc is created, the proc will always have the latest version.
Let’s see an example:
def call_proc(my_proc)
count = 500
my_proc.call
end
count = 1
my_proc = Proc.new { puts count }
p call_proc(my_proc) # What does this print?
In this example we have a local count variable, which is set to 1.
We also have a proc named my_proc, and a call_proc method which runs (via the call method) any proc or lambda that is passed in as an argument.
What do you think this program will print?
It would seem like 500 is the most logical conclusion, but because of the ‘closure’ effect this will print 1.
This happens because the proc is using the value of count from the place where the proc was defined, and that’s outside of the method definition.
The Binding Class
Where do Ruby procs & lambdas store this scope information?
Let me tell you about the Binding class…
When you create a Binding object via the binding method, you are creating an ‘anchor’ to this point in the code.
Every variable, method & class defined at this point will be available later via this object, even if you are in a completely different scope.
Example:
def return_binding
foo = 100
binding
end
# Foo is available thanks to the binding,
# even though we are outside of the method
# where it was defined.
puts return_binding.class
puts return_binding.eval('foo')
# If you try to print foo directly you will get an error.
# The reason is that foo was never defined outside of the method.
puts foo
In other words, executing something under the context of a binding object is the same as if that code was in the same place where that binding was defined (remember the ‘anchor’ metaphor).
You don’t need to use binding objects directly, but it’s still good to know this is a thing 🙂
Video Tutorial
Wrapping Up
In this post you learned how blocks work, the differences between Ruby procs & lambdas and you also learned about the “closure” effect that happens whenever you create a block.
This method allows you to pass in some or all of the required arguments.
If you only pass in a partial number of arguments you will get a new proc with these arguments already ‘pre-loaded’, when all the arguments are supplied then the proc will be executed.
I hope you enjoyed this post!
Don’t forget to subscribe in the form below and share this with your friends 🙂
Good article, Jesus. I think that it is important to understand differences between lambda and proc. This article describe differences politely by coding example, so readers easily understand.
And block is a feature to incarnate Closure.
If Proc.new is called within a method with an attached block, that block is converted to the Proc object.
(example from http://ruby-doc.org/core-2.2.0/Proc.html)
Very helpful, thank you. However there is one think confusing, I checked Kernel module and I see lambda method which is creating Proc object but you mentioned, lambda is a special object of Proc class. Your thoughts?
Some minor nitpicking:
– Blocks are anonymous functions.
– Usually the alternative delimiters to do…end are called “curly braces” or “curly brackets” – “brackets” are (…) if I’m not mistaken.
– There is another, older and thus potentially more compatible syntax to create lambdas: lambda {|arg| …} and lambda do |arg| … end