Understanding the ruby object model
First let us understand what an object is. There could be many ways to explain about object itself, but there are only three conditions that are truly indispensable.
- The ability to differentiate itself from other objects (an identity) → Classification
- The ability to respond to messages (methods) → response_to?
- The ability to store internal state (instance variables)
First things first; everything in Ruby is an object, including classes. The Car class is an instance of class Class. Porsche and Aston Martin are the instances of the class Car which in itself is an object. It might seem weird at first, but this is how Object Oriented Programming is. Not weird, but you always deal with objects. I’ve tried to explain the Ruby Object model with a simple flow diagram.
Let us try and understand each part of the Ruby object hierarchy.
Ruby docs define a Basic Object as the parent class of all objects in Ruby. It’s an explicit blank class.
Why it even exists?
Sometimes you might not want to use the basic object structure that Ruby already provides you so you go to top of the chain and start instantiating objects top to bottom according to your needs. To avoid polluting BasicObject for other users an appropriately named subclass of BasicObject should be created instead of directly modifying BasicObject. Example.
class MyObjectSystem < BasicObject
As can be seen in the flow chart, the BasicObject does not mixes in any module. Hence, modules like Kernel module which provides basic functionality like printing and taking input are also not defined for the BasicObject.
Object inherits from the BasicObject. Object mixes in the Kernel module, making the built-in kernel functions globally accessible.
Modules are a way of grouping together methods, classes, and constants. Modules are about providing methods that you can use across multiple classes — think about them as “libraries”. Classes are about objects; modules are about functions. This stackoverflow neatly defines what modules are used for. They state an example as; authentication and authorization systems are good examples of modules. Authentication systems work across multiple app-level classes (users are authenticated, sessions manage authentication, lots of other classes will act differently based on the auth state), so authentication systems act as shared APIs.
Also, you could achieve multiple inheritance(though it is an anti-pattern) using modules as mixins. You can read more about it here.