Advanced Ruby - Closures and Bindings

Question Click to View Answer

What does the following code print? Explain.

x = 'sir'
y = 'mix-a-lot'
pr = Proc.new do
  "#{x} #{y}"
end

class Dog
  def initialize(pr)
    p pr.call
  end
end

Dog.new(pr)
'sir mix-a-lot'

The pr proc is called in the Dog#initialize method and returns the string 'sir mix-a-lot'. The Dog#initialize method does not have access to x or y, which are local variables defined in the top level scope. When the pr proc is defined, it captures the current scope (including self and the local variable bindings). The proc retains these bindings, even when the scope of the program changes, which meets the computer science definition of a closure.

What does the following code print? Explain.

l = 2
pr = Proc.new { |x| x ** 2 }
h = { me: 'so sleepy' }
h.instance_eval do
  z = 4
  p pr.call(z)
end
p "***"
p pr.call(l)
16
"***"
4

Explain the following sentence: "Procs are first class citizens in the Ruby programming language."

procs can be stored in data structures, passed around as arguments, and returned by methods, thus meeting the definition of a "first class" language component.

Explain the following statement: "Functions are not first class in Ruby. In fact, Ruby doesn't even have functions."

All 'functions' in Ruby are associated with an object, so they're all technically methods. Ruby methods cannot be stored in data structures, passed as arguments, or returned by other methods, so they are not first class. It may appear that Ruby methods can be stored in data structures, but the data structures only store the return value, not the function itself.

class Dog
  def sound
    'woof woof'
  end
end

['a', 'cat', Dog.new.sound]
# => ["a", "cat", "woof woof"]

Notice that the array does not store the actual Dog#sound method, it only stores the return value from the method call.

What does the following code print?

x = 42
y = 'cat'
b = binding
def hi(b)
  b.local_variable_get(:y)
end
p hi(b)
'cat'

The Kernel#binding method captures the local variable bindings and methods that exist when the binding method is called.

What does the following code print? Explain.

class Snake
  def lyric
    x = 'rat'
    y = 'cat'
    z = 'dog'
    binding
  end
end

b = Snake.new.lyric
p eval('"The #{self.class}, the #{x}, the #{y}, the #{z}"', b)
"The Snake, the rat, the cat, the dog"

Binding objects can be used as the second argument of eval() to set the scope. The string of code passed as the first argument in eval() is evaluated in the context of the binding passed in the second argument.

Add code to the following class so Motivation.new.speak returns "Go speed racer!!!"

first = 'speed'
second = 'racer'
class Motivation
  def speak
    # add code here
  end
end
first = 'speed'
second = 'racer'
class Motivation
  def speak
    eval('"Go #{first} #{second}!!!"', TOPLEVEL_BINDING)
  end
end

p Motivation.new.speak

The TOPLEVEL_BINDING constant refers to the top level object. Note that this code will not work if it's pasted into the IRB console, this code must be run from a file with the normal Ruby interpreter.