After graduating from Flatiron School I’ve been going on job interviews and it seems everyone really wants to know how much I know about inheritance. So I told them “I used to work for a living and my grandmother left me nothing.”
After the uncomfortable crickets faded, I told them something like what’s below. I selfishly wrote down some thoughts to solidify my own review of the topic.
Ruby does not have multiple inheritance like some other languages, but it does support this feature through the use of Mixins and you do get to inherit from one super class for free. Since Mixin sounds like we’re cooking something up, let’s define a two classes and a module like this:
1 2 3 4 5 6 7 8 9 10 |
|
Class Vegetable includes a class method cook, and an instance method cook_yo_self.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
|
Class Potato inherits from Vegetable, gaining its methods. So now
1
|
|
are possible. Note that the instance method cook_yo_self from the Vegetable class is inherited, but also overridden by the local definition of the same. So the Potato class definition is the one that outputs, not the Vegetable one. I promise I did that for a reason as we’ll see in a second.
Let’s also look at the module Veg:
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
Class Potato includes and is extended by module Veg. Including it means that the method cry is available to all instances of Potato.
1
|
|
Extending with module Veg means that the class Potato also gains that method
1
|
|
An easy way to remember it that INcluding modules in classes allows INstances access to methods, and Extending doesn’t have an ‘I’ at the beginning. Just remember the first one.
So That’s Super
Defining a new instance of Potato called Russet, and asking it to cook itself results in interesting output:
1 2 3 4 5 6 |
|
The Potato class’s cook_yo_self method should only output “Instance method: would you like fries with that?” But because of the ‘super’ statements, it instead includes the output of each cook_yo_self method from the class, the module and the parent class.
Most interesting is the order in which methods were invoked: first the object’s class, then the included module, and then the parent class. Pretty sweet right? No of course not, they’re potatos. But read here to learn more about the ruby method lookup chain. The order of modules included is in reverse inclusion order, and it also includes methods defined on the singleton.
quick side bar
What is a singleton? The singleton is an object itself. Maybe you want to add functionality to a particular object for testing or some other reason - the look up chain starts at the singleton level, because it is actually possible to do something like this:
1 2 3 4 |
|
I just defined a method on the INSTANCE of Potato called yukon_gold, not the class. And you can do this as well:
1 2 3 4 5 6 |
|
1 2 |
|
These methods are only available on yukon_gold.
side bar over
Notice how Potato’s grow method accesses the constant defined in the Veg module, the double colon allows us to call the constant in the namespace of Veg. That’s the double colon’s job - name spacing.
So how do you get a module into a class?
The whole point of putting things in modules is so that you can modularize and reuse code, so the module is probably defined in a different file than the one you’re working on. The answer is with a require statement. If you’ve saved your modules in ‘modules.rb’, just add in
1
|
|
to your file.