Bird
Raised Fist0
Rubyprogramming~10 mins

Closures and variable binding in Ruby - Step-by-Step Execution

Choose your learning style10 modes available
Concept Flow - Closures and variable binding
Define outer method
↓
Create inner closure (block/lambda)
↓
Inner closure captures outer variable
↓
Return or call closure
↓
Closure uses captured variable
↓
Variable binding shows closure remembers value
This flow shows how a closure captures variables from its surrounding method and remembers their values even after the method ends.
Execution Sample
Ruby
def make_counter
  count = 0
  -> { count += 1 }
end

counter = make_counter
puts counter.call
puts counter.call
This Ruby code defines a closure that remembers and updates a variable 'count' each time it is called.
Execution Table
StepActionVariable 'count'Closure Created?Output
1Enter make_counter methodcount = 0No
2Create lambda closure capturing 'count'count = 0Yes
3Return closure from make_countercount = 0Yes
4Call closure first timecount = 1Yes1
5Call closure second timecount = 2Yes2
💡 Closure calls stop; 'count' variable is updated and remembered inside closure.
Variable Tracker
VariableStartAfter 1st callAfter 2nd callFinal
count0122
Key Moments - 2 Insights
Why does the variable 'count' keep its value between calls to the closure?
Because the closure captures the variable 'count' from the outer method and remembers its state, as shown in execution_table rows 4 and 5 where 'count' increments and keeps its value.
Does the variable 'count' reset to 0 each time we call the closure?
No, it does not reset because the closure holds the binding to the original 'count' variable created in make_counter, so it updates the same variable instead of creating a new one (see execution_table rows 4 and 5).
Visual Quiz - 3 Questions
Test your understanding
Look at the execution_table, what is the value of 'count' after the first call to the closure?
A1
B0
C2
DUndefined
💡 Hint
Check the 'Variable count' column at step 4 in the execution_table.
At which step is the closure created that captures the variable 'count'?
AStep 1
BStep 3
CStep 2
DStep 4
💡 Hint
Look at the 'Closure Created?' column in the execution_table.
If we called the closure a third time, what would be the value of 'count'?
A2
B3
C0
DError
💡 Hint
See how 'count' increments by 1 each call in the variable_tracker.
Concept Snapshot
Closures capture variables from their surrounding method.
They remember and update these variables even after the method ends.
In Ruby, lambdas or blocks can act as closures.
Variable binding means the closure keeps the original variable, not a copy.
Each call to the closure can change the captured variable's value.
Full Transcript
This example shows how Ruby closures work by capturing a variable from an outer method. The method make_counter defines a variable 'count' starting at 0 and returns a lambda closure that increments 'count' by 1 each time it is called. The closure remembers the variable 'count' and its updated value between calls. The execution table traces each step: defining 'count', creating the closure, returning it, and calling it twice. The variable tracker shows how 'count' changes from 0 to 1, then 2. Key moments clarify that the closure holds the variable binding, so 'count' does not reset. The quiz tests understanding of when the closure is created, the value of 'count' after calls, and predicting future values. This helps beginners see how closures keep state in Ruby.

Practice

(1/5)
1. What is a closure in Ruby?
easy
A. A variable that changes its value automatically
B. A method that can only be called once
C. A function that remembers variables from its creation context
D. A class that cannot be inherited

Solution

  1. Step 1: Understand the definition of closure

    A closure is a function or block that keeps access to variables from where it was created, even if called later.
  2. Step 2: Match the definition to options

    A function that remembers variables from its creation context correctly describes this behavior. Other options describe unrelated concepts.
  3. Final Answer:

    A function that remembers variables from its creation context -> Option C
  4. Quick Check:

    Closure = function remembering variables [OK]
Hint: Closures remember variables where they were made [OK]
Common Mistakes:
  • Thinking closures are just methods
  • Confusing closures with classes
  • Believing closures change variable values automatically
2. Which of the following is the correct way to create a closure using a lambda in Ruby?
easy
A. closure = lambda { |x| x * 2 }
B. closure = def(x) x * 2 end
C. closure = function(x) { x * 2 }
D. closure = -> x x * 2

Solution

  1. Step 1: Identify Ruby lambda syntax

    In Ruby, lambdas can be created with lambda { |args| ... } or ->(args) { ... }.
  2. Step 2: Check each option

    closure = lambda { |x| x * 2 } uses lambda { |x| x * 2 }, which is valid. closure = def(x) x * 2 end uses invalid syntax for a lambda. closure = function(x) { x * 2 } uses JavaScript-like syntax. closure = -> x x * 2 misses parentheses in the arrow syntax, which is invalid.
  3. Final Answer:

    closure = lambda { |x| x * 2 } -> Option A
  4. Quick Check:

    Correct lambda syntax = closure = lambda { |x| x * 2 } [OK]
Hint: Use lambda { |args| ... } for Ruby closures [OK]
Common Mistakes:
  • Using JavaScript or Python syntax
  • Omitting parentheses in arrow lambdas
  • Trying to define lambdas with def keyword
3. What will be the output of this Ruby code?
def make_closures
  closures = []
  3.times do |i|
    closures << lambda { i }
  end
  closures
end

closures = make_closures
closures.each { |c| puts c.call }
medium
A. 2 2 2
B. 0 1 2
C. 0 0 0
D. Error: undefined variable i

Solution

  1. Step 1: Understand variable binding in block

    Ruby lambdas capture block variables like i by value in this context, so each lambda remembers its own i value.
  2. Step 2: Evaluate each lambda call

    The loop sets i to 0, 1, 2 sequentially. Each lambda captures the current i value, so outputs are 0, 1, 2 respectively.
  3. Final Answer:

    0 1 2 -> Option B
  4. Quick Check:

    Lambdas capture distinct values per iteration [OK]
Hint: Ruby block vars in closures captured by value per iteration [OK]
Common Mistakes:
  • Thinking lambdas capture shared variable (all 2)
  • Thinking last value is 3 (off-by-one)
  • Expecting error or all zeros
4. Find the error in this Ruby code that tries to create closures:
closures = []
3.times do |i|
  closures << lambda { j }
  j = i
end
closures.each { |c| puts c.call }
medium
A. Variable j is used before assignment inside the lambda
B. Lambda syntax is incorrect
C. times method cannot be used with blocks
D. closures array is not initialized

Solution

  1. Step 1: Identify variable usage inside lambda

    The lambda uses variable j before it is assigned any value in the block, causing an error when called.
  2. Step 2: Understand variable binding timing

    Since j is assigned after lambda creation, the lambda captures j as nil or undefined at call time, causing an error.
  3. Final Answer:

    Variable j is used before assignment inside the lambda -> Option A
  4. Quick Check:

    Use variables after assignment in closures [OK]
Hint: Assign variables before using them in closures [OK]
Common Mistakes:
  • Assuming lambda syntax is wrong
  • Thinking times method is invalid
  • Ignoring variable initialization order
5. How can you modify this Ruby code to create closures that each remember a different value of i even if i changes later?
closures = []
3.times do |i|
  closures << lambda { i }
end
closures.each { |c| puts c.call }
hard
A. Call closures inside the times block
B. Change lambda to proc
C. Use global variable $i instead of i
D. Use a local variable inside the block to capture i: val = i; closures << lambda { val }

Solution

  1. Step 1: Understand variable capture in closures

    Closures capture variables by reference, so if i changes later, all lambdas see the last value.
  2. Step 2: Use a local variable to capture current value

    Assign val = i inside the block, then create lambda using val. This captures the value at that iteration.
  3. Final Answer:

    Use a local variable inside the block to capture i: val = i; closures << lambda { val } -> Option D
  4. Quick Check:

    Capture current value with local variable [OK]
Hint: Assign loop variable to local var inside block for closure [OK]
Common Mistakes:
  • Thinking proc changes variable capture behavior
  • Using global variables which share state
  • Calling closures too early inside loop
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard