What a closure captures
What's already covered
The Ruby blocks (do..end) course's lesson "Proc and lambda: a brief look" already covered real ground. &block turns a passed block into a Proc object, and Proc.new and proc build one directly. .call, .() and [] are three ways to run one. lambda and the ->() { } stabby literal build a stricter version. That lesson named one difference: a lambda raises ArgumentError on a wrong argument count, while a plain Proc lets a missing argument become nil. None of that is repeated here. This course uses Proc and lambda the way that lesson left them, to get at something it never named: the word closure, and what it means.
A method returns, and a value doesn't disappear
def make_greeter(name)
greeting = "Hello"
->(punct) { "#{greeting}, #{name}#{punct}" }
end
g = make_greeter("Ada")
g.call("!")
# "Hello, Ada!"
make_greeter runs, has two local variables, greeting and name, builds a lambda and returns it. By the time g.call("!") runs, make_greeter has finished. Its call is over, and the local variables of a finished method call normally don't exist anymore. Yet g.call("!") reaches greeting and name and produces "Hello, Ada!".
The definition
A closure is a Proc or lambda that captures the local variables in scope when it's created. It keeps live access to them for as long as the Proc or lambda itself is alive, whether or not the method that defined those variables is still running. Every Proc and every lambda in Ruby is a closure. It's a property they both have, not a third kind of object.
Live access, not a snapshot
"Live access" is a claim you can check; it means more than "remembers". Change a captured variable after the closure is created, before you call it, and see which value the closure gets:
def make_reporter
status = "pending"
reporter = -> { status }
status = "done"
reporter
end
r = make_reporter
r.call
# "done", not "pending"
status was "pending" when reporter was created. If a closure copied its captured variables at creation time, r.call would return "pending" forever. It returns "done", so the lambda holds a link to that status variable, not a frozen copy of the value it had when the lambda was built.
Why this matters for the rest of the course
Every remaining lesson depends on this fact. A Proc or lambda is more than "some code to run later": it's code bundled with continuing access to the local variables around it when it was made. The next lesson builds on it. Its method hands back a piece of state that no other code can reach except through the closure it returns.
Key takeaways
- A closure is a
Procorlambdathat captures the local variables in scope when it's created and keeps live access to them after the defining method returns. - Every
Procandlambdain Ruby is a closure; it's a property they have, not a separate kind of object. - Changing a captured variable after the closure is created, before calling it, changes what the closure sees, so it holds a live link and not a snapshot.
- The rest of the course builds on that live access, starting with a method that returns state reachable only through the closure.
Keep going with lesson 2
A counter factory with its own state
Builds make_counter, whose lambda reassigns its own private count, with each call producing independent state.
A free account also gives you the quizzes, your progress and notes, and the discussion.