Chapter 5

How Ruby Borrowed a Decades Old Idea From Lisp

image
The IBM 704, above, was the first computer
to run Lisp in the early 1960s.

Blocks are one of the most commonly used and powerful features of Ruby – as you probably know, they allow you to pass a code snippet to iterators such as each, detect or inject. In Ruby you can also write your own custom iterators or functions that call blocks for other reasons using the yield keyword. Ruby code containing blocks is often more succinct, elegant and expressive than the equivalent code would appear in older languages such as C.

However, don’t jump to the conclusion that blocks are a new idea! In fact, blocks are not new to Ruby at all; the computer science concept behind blocks, called “closures,” was first invented by Peter J. Landin in 1964, a few years after the original version of Lisp was created by John McCarthy in 1958. Closures were later adopted by Lisp – or more precisely a dialect of Lisp called Scheme, invented by Gerald Sussman and Guy Steele in 1975. Sussman and Steele’s use of closures in Scheme brought the idea to many programmers for the first time starting in the 1970s.

But what does “closure” actually mean? In other words, exactly what are Ruby blocks? Are they as simple as they appear? Are they just the snippet of Ruby code that appears between the do and end keywords? Or is there more to Ruby blocks than meets the eye? In this chapter I’ll review how Ruby implements blocks internally, and show how they meet the definition of “closure” used by Sussman and Steele back in 1975. I’ll also show how blocks, lambdas, procs and bindings are all different ways of looking at closures, and how these objects are related to Ruby’s metaprogramming API.

Chapter 5 Roadmap

  1. Blocks: Closures in Ruby
    1. Stepping through how Ruby calls a block
    2. Borrowing an idea from 1975
  2. Experiment 5-1: Which is faster: a while loop or passing a block to each?
  3. Lambdas and Procs: treating functions as a first class citizen
    1. Stack memory vs. heap memory
    2. Stepping through how Ruby creates a lambda
    3. Stepping through how Ruby calls a lambda
    4. The Proc object
  4. Experiment 5-2: Changing local variables after calling lambda
  5. Metaprogramming and closures: eval, instance_eval and binding
    1. Calling eval with binding
    2. Stepping through a call to instance_eval
    3. Another important part of Ruby closures
  6. Experiment 5-3: Using a closure to define a method
  7. Closures in JRuby
  8. Closures in Rubinius