In Ruby, we can use either class inheritance or modules to provide shared functionality throughout a program. This post explores the difference between class inheritance and modules, and considerations to help determine the appropriate use of each.
Class Inheritance
Inheritance between classes in Ruby allows for the creation of classes that have access to shared methods while still maintaining distinct, unique classes. When one class, known as the child or subclass, is inherited from another class, known as the parent or “super” class, it is given access to all of the methods of the parent. For example, we might have a parent class “Dog”, with a child class of “Dalmatian”. In the code below, we define these classes without the use of inheritance.
class Dog
def bark
"Woof!"
end
def sleep
"zzzzz"
end
def find_that_smell
"sniff sniff sniff"
end
end
class Dalmatian
def bark
"Woof!"
end
def sleep
"zzzzz"
end
def find_that_smell
"sniff sniff sniff"
end
end
The acronym DRY stands for "don't repeat yourself", and it is an important principle in software design. In the code below, using class inheritance, we can get the same functionality as above, but we have the benefit of keeping our code DRY. Our Dalmatian class now has access to all of the behavior of the Dog class.
class Dog
def bark
"Woof!"
end
def sleep
"zzzzz"
end
def find_that_smell
"sniff sniff sniff"
end
end
class Dalmatian < Dog
end
The use of inheritance allows us to share methods between classes in a way that reflects the real-world hierarchical relationship between our classes, and provides shared functionality accordingly. If a dog can bark, a Dalmatian can bark.
An important note about class inheritance when considering use is that, although you can inherit from a class that inherits from another class that inherits from yet another class- a single class can only inherit from one class at a time when it is defined.
Modules
Let's imagine we wanted to define an instance method that returns true if the animal is able to be housebroken. We could define this as an instance method within our dog class and have our individual dog breeds inherit the method. But what if our program had other animal classes, such as cats and rabbits, that we wanted to provide this method to as well?
class Animal
end
class Dog < Animal
def can_be_housebroken?
true
end
end
class Cat < Animal
def can_be_housebroken?
true
end
end
class Rabbit < Animal
def can_be_housebroken?
true
end
end
As you can see above, we would have to define those methods over and over again. Sometimes, as in this case, we might want to share functionality between classes that do not have a clear hierarchical arrangement. Instead of making a new class that is built from the blueprint of an existing class, like when we inherit, we may simply want to group methods together and make those methods available to a variety of other classes. Modules allow us to do just that.
Let’s use a module instead of class inheritance. First, we will define our module. Then, within the definition of our classes, we can use the keyword include along with the module name in any number of classes in which we would like to provide access to the functions we defined in our module.
module IndoorPet
def can_be_housebroken?
true
end
end
class Animal
end
class Dog < Animal
include IndoorPet
end
class Cat < Animal
include IndoorPet
end
class Rabbit < Animal
include IndoorPet
end
As you can see, the use of Modules provides a great solution for extending functionality and avoiding repetitive code in situations where there is no clear parent-child relationship. Once it is defined, a module can be included in many classes. There is also no limit to how many modules you can include in an individual class. One thing to keep in mind about modules when considering use is that, unlike with classes, you cannot have an instance of a module.
Class Inheritance vs Modules
Class inheritance and modules both allow us to extend functionality throughout our program while reducing repetitive code. When trying to figure out when to use modules vs class inheritance, some considerations include whether or not you need to create instances, whether or not there is a hierarchical relationship between classes, and how the extended functionality is related to the relationships between groups. If you are trying to build a class from the framework of an already defined class, you can use class inheritance to adopt the behaviors of a parent class. If you've created a group of methods that you’d like to use repeatedly throughout your program in many different classes that are not hierarchically related, you can use modules to provide your classes access to the methods defined within your modules.
In our next post, we dig deeper into modules in ruby, exploring the include
, extend
, and prepend
keywords. You can read that post here.
Top comments (3)
HI, in the example under Modules, why haven't you kept the method can_be_housebroken inside the Animal class so that when the other classes inherit from it they get the method? Instead of creating a module for it. I am not clear with use case here.
@Niyanta Interfaces or Module are used when there is no proper hierarchical relationship
Suppose you keep the method 'can_be_housebroken?' in Animal class,
and you create a childClass Lion from animal. Suppose Lion's house cant be broken , then the method 'can_be_housebroken?' will return true.
Clear and helpful. Thanks!