ruby_cool_kid.rb — Meta Programming series: Like Object, Like Class. Ruby Ancestors I
The phrase “Like father, like son” would be very appropriate for this story. Ruby, as any OOP language, is based on objects, and those objects, can inherit or be inherited (dramatic pause)
After this dramatic pause, let’s start with a concept well known for everybody, a
Class . One would say a class is just a “template” for creating objects in OOP. But, what is really a class in Ruby?
Well, we could say that a
Class is a template for creating an object, but also the sum of its ancestors. Sounds weird right? At this point, one could be wondering what
Class is in Ruby. Here it comes the plot twist,
Class in Ruby is nothing more than an object.
I know it can be confusing and overwhelming, I was in shocked the first time I heard about it. As it seems that it all comes to the objects, let’s see what is an object in Ruby.
Objects in Ruby
Imagine executing the following code:
After running it, if we could look inside
pablo_house object, it would look like this:
Our object (or instance of the class
pablo_housecontains just a reference to its class and its own
instance_variables , but no methods.
If you are a little familiar with Ruby or OOP, you would know that
instance_variables are variables that only live in the object itself, not being shared among objects of the same class. Ruby allows us to obtain them (even though we should not do it) by calling
instance_variables on the object.
On the other hand,
methods in the class are shared among the objects, so they must be stored inside the class.
Bearing this in mind, it is important that we talk properly about methods. Methods defined inside the class, are nothing but
instance_methods (shared among all instances of the class), as we need an object (instance of the class) to call them, but just methods if we talked about them from the object’s perspective.
To put it into real-world words, we could say that
pablo_house has a method called
my_room and, the class
MyHouse , has an
my_room , but we could not say that
MyHouse has a method called
my_room as the class by itself cannot call it.
Ruby speaks this same language so, we could run:
After understanding what an object is, we can go one level up and go back to our main character,
Classes in Ruby
A few lines above we said:
Classin Ruby is nothing more than an object
Therefore, it is obvious that the same principles of the objects apply to it. But wait a minute, if
Class is an object, what is the class of
Don’t panic! Bear here with me, the class of
Class could be obtained by simply running:
Yes! The class of
Class . Funny right? 😜
If you are familiar with the description of
Class from other OOP languages,
Class is just a “read-only description of the class” (from the book Metaprogramming in Ruby 2, by Paolo Perrotta) . This might sound confusing but, in Ruby,
Class is literally the class itself, and can be manipulated as you would do with any other object.
But what could be done with this power? For example, given the dynamic nature of Ruby, defining classes at runtime calling
Class.new , as that new class would just be an instance of
Class being able to call all the
instance_methods available for it. In the end classes, like any object, also have methods.
Given our previous note on methods for an object and a class, what would happen if we execute
Class.instance_methods . Try it. The output should be:
In this output, we can see a really interesting instance method of
Class , which is
:superclass , that is related with the concept of inheritance.
If we were curious and called
String , we would see that the superclass, or parent, of it is
Object , a class that contains useful methods for any object, like
However, if we went up and call
Object , we would get to the top of the Ruby class hierarchy,
BasicObject , which contains just the essential methods for an object.
What about the superclass of
Class ? Well, easy,
Wait, what? 😵
Do not vanish, folks, let’s analyze it, shall we?
Modules in Ruby
Module is the superclass of
Class , so every
Class is also a
Module . Actually, if we take a closer look at their
Class just has three additional methods that
Module does not.
:superclass, :new and :allocate. Surprisingly enough, those are the ones that allow us to create objects and arrange classes into hierarchies.
But, why such difference? Well, it is just a matter of making your code clearer by being more explicit. If we just want to include somewhere the code, we will choose
Module , whereas, if we want to inherit or instantiate that code, we will pick
Class . Easy right?
Taking all the information we gathered, let’s picture it to make it clearer by using our
MyHouse class, as well as its superclasses, thus, inheritance.
Finally, let’s put the cherry on top to end this story.
Anybody that has, anytime, worked with OOP, knows that a variable can reference an object or instance of a class. Thus, it is logical that a variable can reference a class itself because, as we said before,
Class is just an object. Taking this into account, we could:
But …. looks weird right? There is something off. What would happen if we did:
Of course, a variable can be changed, thus losing the class. So, what could we use that can store a reference to the code inside a class and cannot be (or should not be) overwritten 🤔.
Co.. Cons.. Constants you say? Yes! you are completely right! That is why, all the names of classes and modules in Ruby are capitalised, marking their constant nature, in Ruby, everything are constants.
Quick concepts before wrapping up:
- An object is just a bunch of instance variables and a link to a class. Methods don’t live in the object but rather on the object’s class-.
- A class is just an object ( or instance of
Class) that has a bunch of methods and a link to a superclass.
Classis the subclass of
Moduleso, in the end, a class is also a module with instance methods like
- The name of a class must be a constant so that we have a constant (pun intended 😉) reference to it.
This was all for today! Stay tuned for the next episode of Ruby Ancestors, Ruby magic has just begun and everything will make sense in the end. I promise. See you around !!