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 self
inside 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 factorial
.
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 BasicObject
class).
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 to_s
, 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 factorial
function.
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.
Frequently Asked Questions (FAQs) about Ruby’s Top Self Object
What is the significance of ‘self’ in Ruby?
In Ruby, ‘self’ is a special variable that points to the object that is currently being handled. It’s a way for an object to refer to itself. For instance, when you’re defining an instance method within a class, ‘self’ refers to the instance of that class. It’s significant because it allows you to access the current object without knowing its name, providing a way to add flexibility and dynamism to your code.
How does ‘self’ differ in instance and class methods?
In instance methods, ‘self’ refers to the instance of the class. This means you can use it to access other methods and variables within the same instance. On the other hand, in class methods, ‘self’ refers to the class itself. This means you can use it to access other class methods or class variables.
What does ‘def self.function_name’ mean in Ruby?
def self.function_name’ is a way to define a class method in Ruby. The ‘self’ keyword here refers to the class itself, so the method is associated with the class, not its instances. This means you can call the method on the class without creating an instance of it.
Can ‘self’ be used outside of a method in Ruby?
Yes, ‘self’ can be used outside of a method in Ruby. When used outside of a method, ‘self’ refers to the main object, which is an instance of the Object class. This is the default context in Ruby.
How does ‘self’ work in the context of inheritance in Ruby?
In the context of inheritance, ‘self’ still refers to the object that is currently being handled. If a method is called on an object, and that method is defined in the object’s superclass, ‘self’ within that method will still refer to the object, not the superclass.
What is the difference between ‘self’ and ‘@’ in Ruby?
Both ‘self’ and ‘@’ are used to refer to the current object in Ruby, but they are used in different contexts. ‘self’ is used to refer to the current object in a method, while ‘@’ is used to refer to the current object’s instance variables.
Can ‘self’ be reassigned to a different object in Ruby?
No, ‘self’ cannot be reassigned to a different object in Ruby. ‘self’ is a read-only variable, so any attempt to reassign it will result in a syntax error.
How does ‘self’ interact with modules in Ruby?
When ‘self’ is used inside a module, it refers to the module itself. This means you can use ‘self’ to define module methods, which are methods that can be called on the module itself, not on instances of the module.
What is the scope of ‘self’ in Ruby?
The scope of ‘self’ in Ruby depends on where it’s used. Inside an instance method, ‘self’ refers to the instance of the class. Inside a class method, ‘self’ refers to the class. Outside of any method, ‘self’ refers to the main object.
How does ‘self’ work with singleton classes in Ruby?
A singleton class in Ruby is a class that is associated with a specific object. When ‘self’ is used inside a singleton class, it refers to the object that the singleton class is associated with. This allows you to define methods that are specific to that object.
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.