|Creating functions without a class is
awkward in Smalltalk, but simple in Ruby.
Much of Ruby’s implementation of objects and classes is modeled after Smalltalk, one of the original object oriented languages first built in the late 1960s. Just like with Smalltalk, Ruby’s
Object class is the root of your program’s class hierarchy, and all Ruby classes are instances of the
Class class. Smalltalk blocks and Ruby blocks also both support using anonymous functions as closures.
But in one interesting way Ruby and Smalltalk differ. Ruby allows you to define simple functions at the top level scope. This enables Ruby to serve as a scripting language. Using Ruby, it’s very easy to combine a few functions together in a small script to accomplish some simple command line task. At the same time, Ruby’s has Smalltalk’s sophisticated OO design at the ready, waiting for you to use it. When your script gets a bit more complex, you can easily turn it into a more organized, object oriented program.
How does Ruby do this? Before your script starts to run, Ruby automatically creates a hidden object known as the top self object, an instance of the
Object class. This object serves as the default receiver for top level methods. Today we’ll see how this object – the object we didn’t even know we were using – allows us to write simple functions in an object oriented language.
Functions in Ruby
Using Ruby, you can write functions without creating classes for them. For example, here’s the recursive definition of the factorial function in Ruby.
We were able to write a simple function without thinking about methods, receivers, classes or instance variables. We didn’t need any of these concepts, because all we wanted to do was perform a simple calculation. (Advocates of functional programming, of course, would argue you never need OO concepts – that you can and should write your code exclusively with simple functions.)
In this example, Ruby is not a complex, object oriented language, but just a simple scripting language. For many of us, this is how we started using Ruby: At this level, Ruby’s syntax is very straightforward and easy to learn.
Functions Are Methods
However, under the hood Ruby uses a model similar to Smalltalk. There are no functions in Ruby, only methods. Every method belongs to a class.
But what about my factorial example above? Isn’t that a function? I didn’t declare a class or create an object. I just wrote a simple function. If we display the value of
self inside factorial, we’ll see that, in fact, it is a method.
Here you can see Ruby displays the string “main” for the value for
self. Because Ruby defines a value for
factorial, it must be a method.
self contains a reference to the current object, the receiver for the current method. Since
factorial has a receiver it must be a method, not a function.
Seeing Ruby’s Top Self Object
The string “main” is how Ruby represents the top self object as a string. Ruby creates it automatically before you program starts in order to serve as the receiver for functions in the top level scope, such as
In fact, you don’t need to write a method to obtain a value for
self. For example:
Here we are running a one line Ruby script using the
-e option. You can see puts
self returns the string “main.” Another test reveals that the top self object is an instance of
Object, the root class of Ruby’s class hierarchy (aside from the internal
After creating the top self object, Ruby assigns a
to_s method to it which returns the string “main.” Ruby does this using C code internally, but it is equivalent to this Ruby snippet:
You can see self is an instance of
Object. Also notice Ruby defines this special version of the
to_s method only for the top self object. Technically speaking, Ruby creates a singleton class for
self and assigns the new
to_s method to it. (The default version of
Object#to_s, displays the class name and encoded object id instead.)
Of course, you couldn’t write this code yourself, since
self is a reserved word and part of the Ruby language. If you run the code above you’ll get a syntax error “Can’t change the value of self.”
Which Class do Ruby Functions Belong To?
If all Ruby functions are methods, they must belong to some class. But which class? As you might guess, because the top self object is an instance of
Object, Ruby adds all top level functions as methods in the
Object class. Here’s an example.
Here you can see Ruby’s
def keyword saved
factorial as a method in the
Object class. All Ruby functions are actually private methods of
Object. We can prove this is the case by listing the private instance methods of the
Object class, like this.
Calling Ruby Functions
Saving functions as
Object methods isn’t only to preserve Ruby’s (or Smalltalk’s) elegant object oriented design. Internally, it allows Ruby to find functions when your program calls them. Here’s an example.
At the bottom of the diagram I’ve written a new class called
SomeOtherClass. As you can see it contains a single method
show_the_answer which calls the
When I call
factorial, Ruby first looks to see if
factorial is a method of
SomeOtherClass. Because it isn’t, Ruby then looks through the superclasses of
SomeOtherClass to find
factorial. Because Ruby added the
factorial function to
Object, the class of the top self object, Ruby will find it since
Object is a superclass of every other class.
Ruby’s Hidden Object
This might seem like a bit of syntactic sugar. Why does it matter which class Ruby uses to save functions? It fact, does it even matter that functions are methods? They work the same way. And why does the value of self in the top lexical scope matter?
The key point here is that this trick allows you to write simple functions in Ruby. If we weren’t able to write them, Ruby would be harder to learn and more awkward to use. You would have to understand object oriented programming ideas even to get started writing the simplest script using Ruby.
Because it’s hidden, because we don’t know we’re using it, the top self object allows us to use Ruby without object and classes as a simple scripting language. Ruby is much easier to learn than Smalltalk because of the top self object. To learn more about Ruby’s method lookup algorithm, how Ruby implements objects, classes, lexical scope and much more, look for the updated version of my book Ruby Under a Microscope, due out in November from No Starch Press.
Pat Shaughnessy writes a blog about Ruby development and recently self-published an eBook called Ruby Under a Microscope. When he's not at the keyboard, Pat enjoys spending time with his wife and two kids. Pat is also a fluent Spanish speaker and travels frequently to Spain to visit his wife's family.