Inheritance
What are you going to learn?
- Understand what it is inheritance
- Identify when to use inheritance
- Understand how inheritance works in Ruby
What is Inheritance?
Inheritance is a way to define classes that will share their behavior with multiple classes. You can easily reduce the code duplication by defining what is called a Parent class that can be used across multiple subclasses or child-classes.
Inheritance is, at its core, a mechanism for automatic message delegation. It defines a forwarding path for not-understood messages.
In simple words:
- The class being inherited from is called the parent or superclass
- A class can only inherit from one parent. This is not the same to other programming languages.
- Any number of classes can inherit from a single superclass
- When a class inherits from another class, it has access to all of the methods and instance variables from the superclass
- The inheriting class is called the child or subclass
- A subclass parent's parent and so on, is called ancestor
This is how it looks with Ruby code:
# This is the superclass or parent class class Animal end # This is a child class class Cow < Animal end # This is a child class class Duck < Animal end
In the code shown above, < Animal tells Ruby that any class with this snippet will inherit behavior from the Animal superclass. This is not the same as a module,
even though it kind of seems the same. Remember a module also defines namespaces or context.
Whena applying inheritance take this into consideration:
- Inheritance is for specialization, NOT for sharing code.
- You should never inherit from a concrete Class. Always inherit from abstract Classes.
Here is a practical application from Sandi Metz:
Some of [a] bicycle’s behavior applies to all bicycles, some only to road bikes, and some only to mountain bikes. This single class contains several different, but related, types. This is the exact problem that inheritance solves; that of highly related types that share common behavior but differ along some dimension.
Subclasses
We already saw how a subclass looks like, by just adding the < ParentClass to the class definition, and we are ready to go. But's let's build a more comprehensive
example on how this works.
class Pokemon attr_reader :name def initialize(name = "") @name = name end end
We inherit the class Pokemon to the Pikachu subclass
class Pikachu < Pokemon end pikachu = Pikachu.new("Sparky") pikachu.name
As you can see, we did not define the constructor method, nor the name attribute. The pikachu object responded to that because is inheriting all that from Pokemon. The advantage
here is that we can still add methods to the Pikcahu class.
Unlike modules, the methods being inherited are not passed down to the subclass, but are looked up or delegated to the parent class.
Super
There will be a time when you want to extend parts of the behavior you are inheriting, this is when super comes into play. For example if you call the super method inside a subclass initialize
method, it will call the superclass's initialize.
For example:
# pokemon.rb class Pokemon attr_reader :name def initialize(name = "") @name = name end end # pikachu.rb class Pikachu < Pokemon def initialize(name, sound) super(name) @sound = "pika pika" end end
The call super will invoke the initialize method from the Pokemon class, which will set the @name variable. You need to respect the super arguments when it applies, this means that
if the parent class expect to receive 1 parameter, you must add it.
Overrding Methods
As stated in the class lesson, we saw how we can override methods from built-in Ruby classes. This works the same while inheriting from a class. Let's say we have a make_sound
method on the Pokemon class that the Pikachu class will change:
# pokemon.rb class Pokemon attr_reader :name def initialize(name = "") @name = name end def make_sound "" end end # pikachu.rb class Pikachu < Pokemon def initialize(name, sound) super(name) @sound = "pika pika" end def make_sound @sound end end
This will totally override the method, without using any of the superclass implementation. You could use the super clause if you need it.
Properly Applying Inheritance
Subclasses are everything their Superclasses are, plus more. Any object that expect Bicycle should be able to interact with a Mountain Bike in blissful ignorance of its actual Class.
Two things are required for inheritance to work:
- There is a generalization-specialization relationship in the objects you are modeling.
- Correct coding techniques are used.
Exercises
Remember we have provided a repository with a bunch of exercises for you to complete. You can find it here
You can finde them under /ruby-exercises/Module1/inheritance.