Closures in Ruby

Ruby supports anonymous functions, which can form closures. Anonymous functions are useful when you want to define a function inline without having to name it.

# This method int_seq returns a Proc object, which
# we define anonymously in the body of int_seq. The
# returned Proc closes over the variable i to
# form a closure.
def int_seq
  i = 0
  -> { i += 1 }
end

# We call int_seq, assigning the result (a Proc)
# to next_int. This Proc captures its
# own i value, which will be updated each time
# we call next_int.
next_int = int_seq

# See the effect of the closure by calling next_int
# a few times.
puts next_int.call
puts next_int.call
puts next_int.call

# To confirm that the state is unique to that
# particular Proc, create and test a new one.
new_ints = int_seq
puts new_ints.call

To run the program, save it as closures.rb and use the ruby command:

$ ruby closures.rb
1
2
3
1

In Ruby, closures are typically implemented using Proc objects or lambda functions. The -> syntax used in this example is a shorthand for creating a lambda.

The int_seq method returns a new Proc each time it’s called. This Proc maintains its own state (the value of i), which persists between calls to the Proc.

When we call next_int multiple times, we see the value incrementing, demonstrating that the Proc is maintaining its state. When we create a new Proc with new_ints = int_seq, it starts with its own fresh state, separate from next_int.

This example showcases how closures in Ruby can be used to create function factories, each producing a function with its own encapsulated state.