Blocks, Procs, and Lambdas in Ruby
Blocks, Procs, and Lambdas are Ruby’s approach to closures. Let’s start with Blocks.
Blocks
Blocks are any sort of anonymous function that can be passed into methods. The’re the sections of code encapsulated between either braces {}
or do...end
syntax. In short: you’ve probably used them a lot before.
They can be passed to functions as a &block
argument (although the word “block” is purely conventional). Eg:
def powers_of_twoifier(arr, &block)
[1,2,4,8,16].each do |i|
arr.push(block.call(i))
end
end
results = []
powers_of_twoifier(results) do |arg|
arg * 2
end # results = [2, 4, 8, 16, 32]
Blocks can also use yield
instead of block.call
. The difference is that you don’t need to specify &block
in the argument list, it is called implicitly. This is convenient, but if you need to (for example) assign interim values to block
within the method calling it, you’ll obviously want to be able to call it explicitly
Procs & Lambdas
Procs and Lambdas are both blocks that can be assigned to a variable. Eg:
def mathifier(arr, lambda)
res = []
arr.each do |i|
res.push lmb.call(i)
end
return res
end
result = [1, 2, 4, 8, 16]
my_lambda = lambda { |i| i * 2}
doubled = mathifier(result, my_lambda) # result = [2, 4, 8, 16, 32]
Procs are very similar to lambdas, except:
- Lambdas enforce argument count, whereas procs will set unassigned arguments to
nil
, and simply drop excess arguments - Calling
return
in a lambda stops processing of the lambda block, but not the underlying function/code. Callingreturn
in a proc stops both the lambda and the function its nested in