Understanding Ruby closures

Closures are a mainstay of functional languages, but are present in many other languages as well (e.g. Java's anonymous inner classes). They allow deferred execution, and some elegant tricks of style.

Solutions A and B are explanations to Closures described above. Choose the best explanation and explain why it's better.

Solution A
# "In computer science, a closure is a first-class 
# function with free variables that are bound in the lexical environment."
# "A closure is a function that is said to be "closed over" it’s free variables"
# You can pass it around like an object (to be called later)
# It remembers the values of all the variables that were in scope
# when the function was created. It is then able to access those variables 
# when it is called even though they may no longer be in scope.
class SomeClass
  def initialize(value1)
    @value1 = value1
  end
  def value_printer(value2)
    lambda {puts "Value1: #{@value1}, Value2: #{value2}"}
  end
end
def caller(some_closure)
  some_closure.call
end
some_class = SomeClass.new(5)
printer = some_class.value_printer("some value")
caller(printer)
alan@alan-ubuntu-vm:~/tmp$ ruby closures.rb
Value1: 5, Value2: some value
# As you can see, the value_printer function creates a closure, using the lambda construct,
# and then returns it. We then assign our closure to a variable and pass that variable to another function, 
# which then calls our closure. This satisfies the first property of a closure – we can pass it around. 
# Notice also that when we called our closure, we printed out "5" and "some value". 
# Even though both the @value1 and value2 variables were both well and truly out of scope 
# in the rest of the program when we finally called the closure; 
# inside the closure they were still in scope as it retained the state of all the variables that were in scope when it was defined.
# And so, our lambda satisfies the second property also which makes it a closure. 
# I hope the example has made things a bit clearer.
 
Solution B
def make_counter
  n = 0
  return Proc.new { n = n + 1 }
end
c = make_counter
puts c.call # => this outputs 1
puts c.call # => this outputs 2
# The block is not evaluated when make_counter is called. The block is evaluated and run when you call the Proc via c.call. So each time you run c.call, the expression n = n + 1 will be evaluated and run. The binding for the Proc will cause the n variable to remain in scope since it (the local n variable) was first declared outside the Proc closure. As such, n will keep incrementing on each iteration.
# To clarify this further:
# The block that defines a Proc (or lambda) is not evaluated at initialization 
# - the code within is frozen exactly as you see it.
# Ok, the code is actually 'evaluated', but not for the purpose of changing the frozen code. 
# Rather, it is checked for any variables that are currently in scope 
# that are being used within the context of the Proc's code block. 
# Since n is a local variable (as it was defined the line before), 
# and it is used within the Proc, it is captured within the binding and comes along for the ride.
# # When the call method is called on the Proc, 
# it will execute the 'frozen' code within the context of that binding that had been captured. 
# So the n that had been originally been assigned as 0, is incremented to 1. 
# When called again, the same n will increment again to 2. And so on...
 
Log in to accept this challenge
Submitted by others
  • The assignments in solution A makes things more explicit.