First, let's do a little introduction.
Ruby blocks are anonymous functions that can be passed into methods, a way of grouping statements, are passed to methods that yield them within the do
and end
keywords, and they can have multiple arguments.
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.
Lambdas are anonymous functions, objects of the class Proc, they are useful in most of the situations where you would use a proc.
So, procs are blocks, and lambdas are procs, that's because all of them are closures, and they have similar characteristics thanks for this. What is a closure in Ruby? A closure is basically a function that:
- Can be treated as a variable, i.e. assigned to another variable, passed as a method argument, etc.
- Remembers the values of all the variables that were in scope when the function was defined and is able to access these variables even if it is executed in a different scope.
However, what really sets them apart?
What is the difference between Block, Proc, and Lambda?
First, Proc and lambda are objects but blocks are not.
Second, a lambda checks the number of arguments passed to it, while a proc does not.
This means that 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.
Block uses the keyword yield, yield is a Ruby keyword that calls a block when you use it, the code inside the block will run and do its work.
Like in the example below, they all are Ruby blocks:
def print_message
yield
end
print_message { puts "Block message" }
[1,2,3,4].each { |i| puts i }
[1,2,3,4].each do |i|
puts i
end
Third,
when a lambda returns, it passes control back to the calling method,
when a proc returns, it does immediately, without going back to the calling method.
Like in the example below:
def best_movie_proc
movie = Proc.new { return "Harry Potter!" }
movie.call
"Lord of the rings!"
end
puts best_movie_proc # prints "Harry Potter!"
def best_movie_lambda
movie = lambda { return "Harry Potter!" }
movie.call
"Lord of the rings!"
end
puts best_movie_lambda # prints "Lord of the rings!"
See how the proc says "Harry Potter!", this is because it returns immediately, without going back to the best_movie_proc method.
Our lambda, however, goes back into the method after being called, so the method returns the last code it evaluates: "Lord of the rings!"
Calls
Block call
def method
if block_given?
yield
end
end
method { puts "Block message" }
In the given example, we have a block passed with yield keyword.
Proc call
def method(proc)
proc.call # or proc.()
end
my_proc = proc { puts "Proc message" }
method(my_proc)
In procs, we have two different syntaxes, with call
and .()
Lambda call
def method(lambda)
lambda.call # or lambda.()
end
my_lambda = -> { puts "Lambda message" }
method(my_lambda)
Because lambdas are procs, they also have the same call syntax, but they are different to create.
Conclusion
I hope it has become clearer for you to harness the power of Ruby closures.
Top comments (1)
Excellent explanation! thanks for sharing