Closures
In Ruby, procs and lambdas are
closures. The term “closure” comes from the early
days of computer science; it refers to an object that is both an
invocable function and a variable binding for that function. When you
create a proc or a lambda, the resulting Proc object holds not just the executable
block but also bindings for all the variables used by the block.
You already know that blocks can use local variables and method
arguments that are defined outside the block. In the following code, for
example, the block associated with the collect iterator uses the method argument
n:
# multiply each element of the data array by n
def multiply(data, n)
data.collect {|x| x*n }
end
puts multiply([1,2,3], 2) # Prints 2,4,6
What is more interesting, and possibly even surprising, is that if
the block were turned into a proc or lambda, it could access n even after the method to which it is an
argument had returned. The following code demonstrates:
# Return a lambda that retains or "closes over" the argument n
def multiplier(n)
lambda {|data| data.collect{|x| x*n } }
end
doubler = multiplier(2) # Get a lambda that knows how to double
puts doubler.call([1,2,3]) # Prints 2,4,6
The multiplier method returns a
lambda. Because this lambda is used outside of the scope in which it is
defined, we call it a closure; it encapsulates or “closes over” (or just
retains) the binding for the method argument n.
Closures and Shared Variables
It is important to understand that a closure does not just retain ...
Become an O’Reilly member and get unlimited access to this title plus top books and audiobooks from O’Reilly and nearly 200 top publishers, thousands of courses curated by job role, 150+ live events each month,
and much more.
Read now
Unlock full access