Sponsored Link •
Yukihiro Matsumoto, the creator of the Ruby programming language, talks with Bill Venners about two kinds of nameless functions in Ruby, blocks and closures.
Yukihiro Matsumoto, or "Matz," as he is known online, is the creator of the Ruby programming language. Ruby is an object-oriented language suitable for writing day to day scripts as well as full-scale applications. Matz began work on Ruby back in 1993, because he wanted a language that made him productive while being fun to use. Initially popular in Japan, Ruby has been finding its way into the hearts of programmers all over the world.
On September 24, 2003, Bill Venners met with Yukihiro Matsumoto at the JAOO conference in Aarhus, Denmark. In this interview, which is being published in multiple installments on Artima.com, Yukihiro Matsumoto discusses Ruby's design philosopy, the features of the Ruby language, and becoming a better programmer.
Bill Venners: Ruby supports blocks and closures. What are blocks and closures, and how are they used?
Yukihiro Matsumoto: Blocks are basically nameless functions. You
may be familiar with the lambda from other languages like Lisp or Python.
Basically, you can pass a nameless function to another function, and then that function
can invoke the passed-in nameless function. For example, a function could perform
iteration by passing one item at a time to the nameless function. This is a common style,
called higher order function style, among languages that can handle functions as first
class objects. Lisp does it. Python does it .Even C does it with function pointers. Many
other languages do this style of programming. In Ruby, the difference is mainly
a different kind of syntax for higher order functions. In other languages, you have to
specify explicitly that a function can accept another function as an argument. But in
Ruby, any method can be called with a block as an implicit argument. Inside the method,
you can call the block using the
yield keyword with a value.
Bill Venners: What is the benefit of blocks?
Yukihiro Matsumoto: Basically, blocks are designed for loop abstraction. The most basic usage of blocks is to let you define your own way for iterating over the items.
For example, if you have a list, sequence, vector, or array, you can iterate forward by
using the method provided by the standard library. But what if you want to iterate
backwards from the end to the beginning? In C, you have to set up four things: an index, a
start value, an end comparison, and an increment. This is not good, because it reveals
internal details of the list. We want to hide that logic. By using blocks, we can hide the
loop logic inside the method or function. So for example by calling
list.reverse_each , you can do a reverse iteration over the list without knowing
how the list is implemented on the inside.
Bill Venners: I just pass in a block that's going to do whatever I want to do with each element, and it's up to the list to know how to go backwards. In other words, I pass as a block whatever code I would have put inside the for loop in C.
Yukihiro Matsumoto: Yes, and that also means you can define many ways to iterate. You could provide a forward way to iterate, a backward way, and so on. It's up to you. C# has an iterator, but it has just one iterator per class. In Ruby you can have an arbitrary number of iterators if you want. If you have a tree class, for example, which you think people will want to traverse depth first and breadth first, you can provide both kinds of traversal by providing two different methods.
Bill Venners: Let me see if I understand this. In Java, they
abstract iteration with
Iterators. A client can ask a
Collection for an
Iterator, for example. But the client must
use a for loop that runs through and processes the items returned by the
Iterator. Inside the for loop, I have "the code" that I want to perform on
each item, so that for loop always shows up in the client code. With blocks, I don't call a
method to get an
Iterator back, I call a method and pass as a block "the
code" I want to process each item of the iteration. Is the benefit of the block
approach that it takes a little bit of code, the for loop, out of each client?
Yukihiro Matsumoto: The details of how to iterate should belong to the service provider class. The client should know as little as possible. That was the original purpose of blocks. In fact, in early versions of Ruby, the methods called with blocks were referred to as iterators, because they were designed to iterate. But in the history of Ruby, the role of blocks was later enhanced from loop abstraction to anything.
Bill Venners: For example...
Yukihiro Matsumoto: For example, we can create a closure out of a block. A closure is a nameless function the way it is done in Lisp. You can pass around a nameless function object, the closure, to another method to customize the behavior of the method. As another example, if you have a sort method to sort an array or list, you can pass a block to define how to compare the elements. This is not iteration. This is not a loop. But it is using blocks.