Ruby — Proc, Block & Lambda — What’s the Confusion?
In this article, we will understand about the block, proc, and lambda in Ruby. After going through the article we would know better about what they are, how they work, and what are the differences or similarities between them.
Block — Simply Solved😌
Blocks are a small anonymous function passed into a method. So don’t get confused they are just a few lines of code enclosed either into brackets ({}) or do-end passed into the method as an argument and called in the method through using the yield keyword. Let’s see an example:
def simple_block
puts "Inside Method"
yield 1
yield 2
puts "After the Block Call"
end
simple_block { |a| puts "Hey Block Called #{a} time" }
# Inside Method
# Hey Block Called 1 time
# Hey Block Called 2 time
# After the Block Call
# Explicit Block used as variable
def simple_block(&name)
puts "Inside Method"
yield 1
yield 2
name.call(3)
puts "After the Block Call"
end
simple_block { |a| puts "Hey Block Called #{a} time" }
# Inside Method
# Hey Block Called 1 time
# Hey Block Called 2 time
# Hey Block Called 3 time
# After the Block Call
From the above example, it might be very clear how the block actually works. We passed the block in the method in two ways — Explicit(using a variable name) and Implicit(directly without a name).
Proc — The major Class🤔
Procs are similar to blocks in working but they can be assigned to a variable where blocks cannot be assigned to a variable. To make it more clear when we see the block class, it tends to belong to the Proc class. This means it’s clear that all blocks, either simple Block, Proc Instance, or Lambda, belong to the same class that is Proc. Let us first see the Proc with example:
def proc_blocks(proc_block)
puts "Inside Method"
# Different types we call a Proc
proc_block.call 1
proc_block.(2)
proc_block.[] 3
proc_block.===4
# Yield can't be used as Block been passed as a variable not Block
puts "After Block Call"
end
p1 = Proc.new { |a| puts "Hey Block Called #{a} time" }
proc_blocks(p1)
# Inside Method
# Hey Block Called 1 time
# Hey Block Called 2 time
# Hey Block Called 3 time
# Hey Block Called 4time
# After the Block Call
def simple_block(&name)
puts "Inside Method"
puts name.class
puts "After the Block Call"
end
simple_block { |a| puts "Hey Block Called #{a} time" }
# Inside Method
# Proc
# After the Block Call
In this example, it had been clear that the block is an instance of the Proc directly.
Lambda — Why another way?🤔
Lambda is also the instance of the Proc class which has its own syntax to be defined. Lamda can also be assigned to a variable and can be called the same as Proc. Let’s first get through lambda syntax and example, then we will know the difference between them:
def lambda_blocks(lambda_block)
puts "Inside Method"
# Different types we call a Lambda
lambda_block.call 1
lambda_block.(2)
lambda_block.[] 3
lambda_block.===4
# Yield can't be used as Block been passed as a variable not Block
puts "After Block Call"
end
p1 = -> (a) { puts "Hey Block Called #{a} time" }
lambda_blocks(p1)
# Inside Method
# Hey Block Called 1 time
# Hey Block Called 2 time
# Hey Block Called 3 time
# Hey Block Called 4time
# After the Block Call
It’s weird if lambda, Block, and Proc are the same why do we have different versions same block functionality?
Not Same At All— Let’s see
- Proc and Block do not care about the arguments passed, while lambda throws an Argument error whenever the wrong number of arguments are passed.
- If a Proc contains a return it will return the whole method from the same place without performing the rest of the method code while lambda returns from itself and performs the rest of the method code.
lambda_block = -> (a){ puts "Hey Block Called #{a} time" }
lambda_block.call
# Throws error- wrong number of Arguments
proc_block = Proc.new { |a| puts "Hey Block Called #{a} time" }
proc_block.call
# Hey Block Called time
# return after executing the whole method - Lambda
def differntiate_block(lambda_block)
puts "Inside Method"
lambda_block.call 1
puts "After Block Call"
end
lambda_block = -> (a) do puts "Hey Block Called #{a} time"
return 2
end
# Inside Method
# Hey Block Called time
# After Block Call
# return after executing Proc return statement
def differntiate_block(proc_block)
puts "Inside Method"
proc_block.call 1
puts "After Block Call"
end
proc_block = Proc.new do |a| puts "Hey Block Called #{a} time"
return 2
end
# Inside Method
# Hey Block Called time
Conclusion
Although the working of the Block, Proc, and Lambda is similar, the certain differences above make their use case more specific in their type. So be attentive to how we can use them.