In the same way Eurasier puppies inherit attributes and behaviors from their parents, or heirs receive assets from the deceased, Ruby classes can inherit methods and behaviors from their superclasses. This functionality is fundamental to object-oriented programming, allowing for the creation of increasingly specific subclasses by leveraging method reusability. A child (subclass) inherits all the methods of its parent (superclass), and can increase in specificity depending on the programmer’s needs. These capabilities are illustrated in the following example:
On line 7 in the example (above), the subclass
Bulldog inherits the methods from its superclass
Dog using the
< key. The
Bulldog class inherits the
#speak method and becomes increasingly specific by introducing a new
#sleep method unique to itself. When the
Bulldog instance of
baby is created, it’s clear that she has the ability to both
Now imagine a scenario where a new subclass of
Dog is required, but this specific type of dog’s speaking would be better described as
“Yip” instead of
In Example 2 (above), both the
Schitzu subclass and the
Dog superclass contain a method with the same name. When an instance of
Schitzu is created, and
#speak is called on it, the behavior inherited from the
Dog class is overridden. If for some reason the programmer desires the
#speak behavior from the superclass, and doesn’t want it to be overridden by
Schitzu, the super keyword can be utilized.
The super keyword is used to call a method of the same name in the superclass.
matilda is now expressing the
#speak behavior of its superclass
Dog, even though it has a method of the same name.
The Ancestors Chain
In the next section, different methods of inheriting behavior from classes and modules will be explored.
.ancestors is a class method in Ruby that returns an array of classes and modules commonly known as the ancestors chain. The order of the elements in this array are listed in a hierarchy of increasing parent rank.
puts String.ancestors# => [String, Comparable, Object, Kernel, BasicObject]
.ancestors method is called on the
String class, its respective ancestors chain is returned. From the top down
BasicObject is the parent class of all Ruby classes,
Kernel is its child module,
Object is the child class of
Comparable is the child module of
Object and the superclass of
When a method is called, a lot happens under the hood. Through the process of method lookup, the chain is referenced, and the method is executed using the instructions defined in the first class or module that appears in the ancestors chain containing that method name.
The above example utilizes the include keyword. This keyword is another way to express inheritance in Ruby. The included object is placed directly after the object that includes it in the ancestors chain. The ancestor chain in the above example is expressed as:
[AstroPhysics, Physics, Science, Object, Kernel, BasicObject]
AstroPhysics, the object that
.ancestors was called on is the first in the chain, followed by its parent
Physics, followed by its parent
Science, etc. Typically, the object that
.ancestors was called on, is first in the chain. However, there is one keyword that makes an exception: prepend.
Note that in the above example,
Harvard.ancestors was called, but the first module in the chain was
LawSchool. The prepend keyword places
LawSchool in front of Harvard in the ancestors chain.
puts Harvard.ancestors# => [LawSchool, Harvard, University]
Imagine a situation where all of the class/module objects contain a method named
scale. The ancestors chain can be a useful tool to use when trying to figure out what instructions for
scale to follow. When viewing the ancestors chain, the object hierarchy in Ruby can be clearly visualized. Example 6 illustrates this point.
Drum class includes the
Instrument module containing the
scale method. However, because
Drum also includes a
scale method, the ancestors chain tells the programmer that the
scale method in the
Drum class will take priority over all of the other objects in the chain.