July 11, 2020
I was recently asked in an interview what the difference between modules and inheritance in Ruby is, and when I would use one over the other. I struggled a bit to come up with a clear answer, so I knew it was time to brush up on my Ruby!
Ruby is an Object-Oriented Programming (OOP) language, and classes are the fundamental building blocks of OOP. Classes are blueprints for creating objects, and describe the behavior and properties each instance will have. Let’s say, for example, that I am a person. I am an individual instance of a person, Shane. All people share specific properties, such as having a name, eating, drinking, sleeping, etc. In Ruby, you could say I belong to the Person
class, which contains all these shared properties and behaviors. Classes are the re-usable blueprint that let you create each individual instance.
Now, let’s say you have multiple classes that share behaviors. Instead of rewriting all that code in each class, Ruby provides a few ways to create reusable code. In this post I will walk you through two ways to provide reusable behaviors to classes: inheritance and modules.
If you want to create a class which has all of the attributes and methods of another class, but is more specified, you can use inheritance. By inheriting from a parent class, the child class will have access to all behaviors the parent has. For example, a Singer
is a more specific version of a Performer
, which is a more specific version of a Person
. A Performer
would inherit all the behavior of a Person
, and a Singer
would inherit from a Performer
. In Ruby, it would look like this:
class Personendclass Performer < Personendclass Singer < Performerend
All methods and properties defined in Person will be available in Singer, but not everything in Singer will be available in Person. The most generic classes live at the top level, and things get more specific as you move down levels. Lets go ahead and build out this classes more to demonstrate.
class Persondef eatputs "Nom Nom Nom"enddef drinkputs "Slurp"enddef sleepputs "ZZZzzz"endendclass Performer < Persondef razzle_dazzleputs "🎉 🎉 🎉"endendclass Singer < Performerdef singputs "🎶 La La La 🎶"endend
Now, we can create a few instances of these classes and see exactly who has access to which methods.
john = Person.newhugh = Performer.newwhitney = Singer.newjohn.eat # ✅john.razzle_dazzle # ❌hugh.razzle_dazzle # ✅hugh.sing # ❌whitney.sing # ✅whitney.razzle_dazzle # ✅whitney.sleep # ✅
What if we have a separated set of methods we want to be able to add to any class in any inheritance chain? We can use a module! A module is similar to a class in that it contains methods in order to be re-used. Modules can not be instantiated though, meaning you can not create a new instance using the new
method. Modules can be included inside a class, giving that class access to anything contained within the module.
module BreathSupportdef deep_breathputs "💨"endendclass Singer < Performerinclude BreathSupportdef singputs "🎶 La La La 🎶"endendclass Actor < Performerinclude BreathSupportdef monologueputs "To be or not to be... 💀"endendaudra = Singer.newkenneth = Actor.newaudra.deep_breath # ✅kenneth.deep_breath # ✅
Now any instance created from either the Actor
or Singer
class will have access to the deep_breath
method defined inside the BreathSupport
module.
So, when should you use a module instead of inheriting from a class? A good rule of thumb is to consider is whether or not you will want to create an instance based on the functionality you desire. If so, you will want to create a class as you cannot create instances of modules. If not, you can likely use a module to accomplish the behavior you want, and it can be included in any classes which require it. Additionally, if you want to create a blueprint that is a more specific version of a class that already exists, including all of the contents of that class, that would be the perfect time to use inheritance.
You now know how to get started working with class inheritance and modules in Ruby, and when you might want to use them. Thank you for reading, and good luck with your projects!
The personal blog of Shane Lonergan. NYC based software engineer, actor, director, and musician. Documenting my journey from the stage to the computer screen. To keep up to date, you should follow me on Twitter.