The Ruby Object Model: Exploring How Ruby Is Built Up On The Inside. PART I
My recent journey inside the Ruby Programming Language has revealed many interesting things that I did not know before. This short write up talks about a couple of things I discovered through a lot of reading and experimenting with ruby(in an irb session). To follow this tutorial I’ll advise you fire up your irb session.
NOTE: My ruby version is 2.2.1.
There are a couple of things I would like for you to take note before we begin our deep dive into the Ruby Object Model.
- In Ruby, everything is an object. Even classes too. Classes are sometimes referred to as class objects(a reference I tend to use a lot). Class objects are the only objects that have an instantiation capability.
- Every class created in Ruby is an instance of class Class(Class is a built-in class in Ruby).
- Every method in Ruby is an instance method of some sort. It just depends on where they are defined.
- Every object has a singleton class wired up with it.
5. Every object inherits directly or indirectly from Object(Ruby built-in class) BasicObject is the only built-in class that has no superclass.
6. Also, there’s nothing like class methods in Ruby. What is commonly referred to as class methods are in fact singleton methods(or, instance methods defined on singleton classes of class objects).
Ok, let’s get dive.
In Ruby, objects(which are instances of classes) are represented differently internally from classes. Internally, objects store instance variables that reference some object, as well as have a pointer to the class from which it was instantiated. However, ruby objects do not store of have methods, internally speaking. Only classes do. Below is an example I cooked up in my irb session to illustrate the point.
In the example above you can see the user.class produces User. The following expression, _.class(in irb, _ refers to the result of the previous expression, in this case User) gives us Class, meaning User is an instance of Class. We can also see the instance_variables that this object stores by calling the method user.instance_variables.
Classes in Ruby are also objects too. They are sometimes referred to as class objects because they are the only objects endowed with instantiation capability. In Ruby, a class can store methods, instance variables and constants, has a pointer to it’s class which is class Class, as well as a pointer to it’s superclass.
Below is an example to illustrate the point.
In above example, we can view the instance methods defined only in User(by supplying false as an argument we tell Ruby not traverse the entire inheritance chain for instance methods). We also see User.class gives us class Class and that User has a superclass of Object. Note that any class defined in Ruby with out an explicit parent class means that class implicitly inherits from Object directly. Before we proceed here is a conceptual diagram to illustrate the distinction between classes and objects as represented internally in Ruby.
In the Ruby world, the term class methods gets thrown around a lot. It usually defines methods that can be called on a class. For example, the method superclass is a class method that can be called on the class User. But this nothing more than a “conceptual” term. Ruby doesn’t really have class methods(as if ruby 2.2.1). It instead has singleton methods. In order to describe effectively what singleton methods are, I will have to introduce another term called the singleton class. In Ruby, every object is wired up with a singleton class. Essentially, a singleton class(also known as eigenclass, or metaclass) is a “special” class in Ruby that allows you to define methods that are applicable to only a single object. Sounds abstract, right? Below is an irb example that shines more light on this confusing concept.
The above example illustrates the fact that objects are wired up with a singleton class. SomeClass has 2 methods; one instance method called some_instance_method and one class method called some_class_method.
An instance of SomeClass, which is some_obj, has a singleton class and we find this by calling the method singleton_class on it. Note how singleton classes are represented, with a #<Class: prefix. Even SomeClass, a class, which is also an object(class object), has it’s own singleton class. SomeClass.singleton_class gives us #<Class:SomeClass>, Ruby’s representation of SomeClass’s singleton class.
The purpose of singleton classes allows us to define what we commonly refer to as class methods, or singleton methods. Singleton methods are really instance methods defined in singleton class. In the above example, we defined one class method. If you ask Ruby what this method is and where is located you get the following:
First, we find out that some_class_method is a singleton method. Secondly, we create a method object which allows us to find out where this method is actually defined by calling .owner on the method object. (more on method objects). We find out the owner is a singleton class.
Also to prove that singleton methods are really just instance methods defined in singleton class below is an illustration:
Apart from allowing us to define class methods/singleton methods, singleton classes provides us with the ability to define methods unique to a single object.
Below illustrates this point:
In the above example, we create a singleton method called some_unique_method on obj1. This method is unique because obj2 doesn’t respond to it, even though it shares the same class as obj1. We also see that this method is defined in obj1’s singleton_class…
This ends part I of the series.