Inheritance in Ruby: Understanding the “super” keyword

Daniel Mekuriaw
Jun 22 · 5 min read

Although the idea of inheritance is pretty straightforward, its implementation in Ruby as well as the use of the “super” keyword is troublesome for beginner Rubyists and/or those new to the idea of object-oriented programming (OOP).

This blog discusses how inheritance works in Ruby, with a particular focus on the use of the “super” keyword. Through code snippets and examples, this blog presents this implementation in a way that a beginner Rubyist can easily understand.

What is inheritance in OOP?

Inheritance is one of the many core concepts of OOP, and it refers to the method of deriving a class from another class that shares a set of attributes and methods. This is an essential OOP concept as it opens the door for reusability, which translates to writing fewer lines of codes and avoiding repetitions when it comes to writing code. By modeling a hierarchical relationship between different classes that share certain characteristics and behaviors, the amount of code that needs to be required can be significantly reduced.

https://tutorials.supunkavinda.blog/php/oop-inheritance

At its most basic level, inheritance can be understood through the diagram to the left. This diagram shows a Dog and a Cat children classes inheriting from a parent Animal class. This is possible because both dogs and cats are animals, and share certain characteristics that define what animals are. Hence, by factoring out common features and creating parent classes from which children classes can inherit, inheritance can be achieved.

Ruby Syntax for Inheritance

class Animal    def i_am_animal_sentence
puts "I am an animal!"
end
endclass Cat < Animal def i_am_a_cat
i_am_animal_sentence
end
endclass Dog < Animal def i_am_a_dog
i_am_animal_sentence
end
end

As can be seen in the example code snippet above, both the Cat and Dog classes inherit the Animal class, which means that an instance of either the Cat or Dog class will have the #i_am_animal_sentence method to print the “I am an animal!” sentence since the parent class for both classes includes this method. This means:

cat1 = Cat.new
cat1.i_am_a_cat
#=> "I am an animal!"
dog1 = Dog.new
dog1.i_am_a_dog
#=> "I am an animal!"

Since the #i_am_animal_sentence instance method is available for both the Dog and Cat classes, and since the #i_am_a_cat and #i_am_a_dog methods in these classes call the #i_am_animal_sentence method, the “I am an animal!” sentence is printed out with the call of both methods. This goes to show that if we have any repeated code for two different classes, in this case printing out the “I am an animal!” sentence, we can write a parent class from which the children classes can inherit. In this example, the parent class was the Animal class, and it included the shared functionalities.

Augmenting Inherited Methods

Therefore, how do can we modify methods while preserving parts of their functions?

This is where the “super” keyword comes in. This keyword is called within a method and tells Ruby to inherit all the functionalities of a method of the same name in the parent class, and then it gives us the option to add more functions and do more with the inherited functionalities.

For instance,

class Animal    def i_am_animal_sentence
puts "I am an animal!"
end
endclass Cat < Animal def i_am_animal_sentence
super
puts "I am a cat!"
end
endclass Dog < Animal def i_am_animal_sentence
super
puts "I am a dog!"
end
end

Now, we can call the #i_am_an_animal_sentence method on either a Cat or a Dog instance and get the functionalities of the method in the parent class along with what we augmented using super as can be seen below:

cat1 = Cat.new
cat1.i_am_an_animal_sentence
#=> "I am an animal!"
"I am a cat!"
dog1 = Dog.new
dog1.i_am_an_animal_sentence
#=> "I am an animal!"
"I am a dog!"

Therefore, “super” allows us to add features to existing methods inherited from parent classes. This opens the door for more flexibility while maintaining the organized nature of object-oriented programming.

Although not very relevant when starting to learn Ruby, it is important to know that Ruby does not support multiple class inheritance. Rather, supports only single class inheritance. This means that a single class can inherit properties and methods from a single parent class and not others. This is shown through the demonstration below:

class Animal    def i_am_animal_sentence
puts "I am an animal!"
end
endclass Fourlegs def i_have_four_legs
puts "I have four legs!"
end
endclass Cat < Animal < Fourlegs def i_am_animal_sentence
super
i_have_four_legs
puts "I am a cat!"
end
endclass Dog < Fourlegs < Animal def i_am_animal_sentence
super
i_have_four_legs
puts "I am a dog!"
end
end

If we try to call the classes we just defined, regardless of the order in which we are trying to inherit the classes, we would get errors as follows:

cat1 = Cat.new
cat1.i_am_an_animal_sentence
#=> superclass must be a Class (NilClass given) (TypeError)
dog1 = Dog.new
dog1.i_am_an_animal_sentence
#=> superclass must be a Class (NilClass given) (TypeError)

This error occurs because Ruby doesn’t recognize the “<” symbol when it appears for the second time in the definition of a class. One way to work around this is linking the classes with one another, creating a one-to-one inheritance dependency chain. So, in the case of the example above it is possible to have the Fourlegs class inherit the Animal class and the other two classes inherit this Fourlegs class (like shown in the snippet below), instead of trying to do multi-class inheritances all at once. That way, the methods in both Fourlegs and Animal classes will be accessible in both the Cat and Dog classes.

class Animal
...
end
class Fourlegs < Animal
...
end
class Cat < Fourlegs
...
end
class Dog < Fourlegs
...
end

There is also a way to work around this multi-class inheritance limitation using mixins, but it will not be discussed under this.

In conclusion, as one of the most powerful OOP languages, Ruby allows us to implement a single-class inheritance. Through the “<” key symbol, we can create inheritance dependencies between different classes with common features, while using the “super” keyword allows us to inherit functionalities and add some modifications to the outputs of certain methods. Hence, by implementing the idea of inheritance with Ruby, you can save yourself from having to write redundant and bulky code!

Works Consulted

Geek Culture

Proud to geek out. Follow to join our 1M monthly readers.