13. Inheritance

And we’re back! Welcome to the fourth and last theoretical lesson on object-oriented programming. In this one, we’re going to look at one of the most powerful mechanisms in your object-oriented programming arsenal: inheritance.

The DRY Principle

Before delving into the inheritance magic, let’s take a minute to introduce the DRY principle. DRY is an acronym for Don’t Repeat Yourself. In essence, it means that code shouldn’t be duplicated. If, in your program or library, you have some code that does something, you shouldn’t duplicate it somewhere else to replicate this functionality. Each piece of code should be unique and take care of one particular task. Each time you feel like copy-pasting a bit of code, an alarm should trigger in your head and you should pause and figure out whether there’s an alternative approach that doesn’t involve duplicating code.

For example, if you find yourself repeating the same group of statements multiple times in your program, take this group of statements, wrap them in a function and call this function when you need it. Okay, that’s a mouthful and it sounds kind of complicated but if you recall your second lesson on functions, we did exactly that! Let’s revisit it, to illustrate the DRY principle:

Not DRY:

func Main() {   Stand up   Go to the coffee machine   Press the 'coffee' button   Wait for the cup   Take the cup   Deliver the cup to John    Stand up   Go to the coffee machine   Press the 'coffee' button   Wait for the cup   Take the cup   Deliver the cup to Linda    Stand up   Go to the coffee machine   Press the 'coffee' button   Wait for the cup   Take the cup   Deliver the cup to Tyrion } 

DRY:

func MakeCoffee() -> Cup {   Stand up   Go to the coffee machine   Press the 'coffee' button   Wait for the cup   Return the cup }  func Main(){   Deliver MakeCoffee() to John   Deliver MakeCoffee() to Linda   Deliver MakeCoffee() to Tyrion } 

The above examples both produce the same result but the second one is shorter to type, easier to read and faster to change. For example, if in the future we had to change the logic or add a statement such as Insert coin before Press the 'coffee' button, we would only need to add it once within the MakeCoffee function. As we will soon see, designing software with change in mind is an excellent practice. The DRY principle allows us to do just that, whilst also keeping our code succinct and readable.

Similar Classes

Now that you know how to write and read what a class does, have a look at these two similar yet different classes. Don’t rush. Take your time to understand what they do and which objects they can create:

Cat

class Cat {    Name as String   Weight as Float   Color as String    func Init() {     self.Name = "Unknown"     self.Weight = 0.0     self.Color = "Undefined"   }    func Walk() -> String {     return self.Name + " is walking."   }    func Sleep() -> String {     return self.Name + " is sleeping."   }  } 

Dog

class Dog {    Name as String   Weight as Float   Color as String    func Init() {     self.Name = "Unknown"     self.Weight = 0.0     self.Color = "Undefined"   }    func Walk() -> String {     return self.Name + " is walking."   }    func Sleep() -> String {     return self.Name + " is sleeping."   }  } 

In the code above, we have two classes. One that represents a Cat and one that represents a Dog. However there is so much repeated code, it hurts! In reality, the only difference between our computerized dog and cat is the class name. Inheritance to the rescue!

The Base Class

Consider the code below, that presents 3 classes. Read them and try to figure out what they mean.

Animal

class Animal {    Name as String   Weight as Float   Color as String    func Init() {     self.Name = "Unknown"     self.Weight = 0.0     self.Color = "Undefined"   }    func Walk() -> String {     return self.Name + " is walking."   }    func Sleep() -> String {     return self.Name + " is sleeping."   }  } 

Cat

class Cat: Animal {  } 

Dog

class Dog: Animal {  } 

So, did you figure out what these three classes do? The first one, Animal represents a generic animal. We don’t know exactly which animal, just that its an animal. It has some properties and methods. The Cat class is said to inherit from Animal. You see that from the line class Cat: Animal. The colon (:) translates to inherit from in programmer’s lingo. In English, it would translate to “is a…..”. Therefore, Cat is an animal.

This “is a” relationship means that all the properties and methods that are implemented within the Animal class are also available in the Cat class. Same goes for the Dog class since Dog is also an Animal. This, in a nutshell, is the concept of inheritance.

Animal would be described as the base class or parent class.

Cat and Dog would each be described as a child class.

Child Class Usage

Let’s write a small program using the classes we just created. Let’s also pretend that we saved our three classes, Animal, Cat and Dog in a library named AnimalsLibrary.

What would you expect to be displayed on the screen if we ran this program?

Think it through and try not to peek at the answer below until you’ve got your answer!

import AnimalsLibrary  func Main() {    myCat = new Cat   myDog = new Dog    myCat.Name = "Spock"   myDog.Name = "Gandalf"    Display myCat.Sleep()   Display myDog.Walk()  } 

…and this is the result:

Spock is sleeping. Gandalf is walking. 

How was this possible? Because of inheritance. Both myCat object and myDog object inherited their properties and methods from the Animal class.

Specific Members

So far, the examples have been trivial because both Cat and Dog had the exact same members (properties and methods). What if we wanted to have a method named Eat but only for the Cat, not the Dog? Easy! We would implement the Eat method directly in the Cat class instead of doing so within the Animal class.

Like so (pay attention to the modified Cat class):

Animal

class Animal {    Name as String   Weight as Float   Color as String    func Init() {     self.Name = "Unknown"     self.Weight = 0.0     self.Color = "Undefined"   }    func Walk() -> String {     return self.Name + " is walking."   }    func Sleep() -> String {     return self.Name + " is sleeping."   }  } 

Cat

class Cat: Animal {    func Eat() -> String {     return self.Name + " is eating."   }  } 

Dog

class Dog: Animal {  } 

Now, a cat can eat but a dog can’t. A fairly unacceptable state of affairs for any self respecting dog! The dog cannot eat because there is no Eat method inside the Dog class nor within the Animal class. A dog object wouldn’t be able to call the Eat method because it can’t inherit it from Animal and because a dog is not a cat.

Let’s modify our previous program:

import AnimalsLibrary  func Main() {    myCat = new Cat   myDog = new Dog    myCat.Name = "Spock"   myDog.Name = "Gandalf"    Display myCat.Eat()   Display myDog.Eat()  } 

The result on the screen would be:

Spock is eating.  

Overriding

Lets take our examples a step further. Assume we want the Sleep method to return “name-of-the-dog is taking a nap.” for a dog object and “name-of-the-cat is sleeping.” for a cat object. We would achieve this by providing an override to the Sleep method within the Dog class. Put simply, this means that we would provide our own version of the Sleep method in the Dog class rather than letting it use the Sleep method implemented in the Animal base class. Pay close attention to the changes in the Dog class:

Animal

class Animal {    Name as String   Weight as Float   Color as String    func Init() {     self.Name = "Unknown"     self.Weight = 0.0     self.Color = "Undefined"   }    func Walk() -> String {     return self.Name + " is walking."   }    func Sleep() -> String {     return self.Name + " is sleeping."   }  } 

Cat

class Cat: Animal {    func Eat() -> String {     return self.Name + " is eating."   }  } 

Dog

class Dog: Animal {    func Sleep() -> String {     return self.Name + " is taking a nap."   }  } 

Again, let’s modify our program as below:

import AnimalsLibrary  func Main() {    myCat = new Cat   myDog = new Dog    myCat.Name = "Spock"   myDog.Name = "Gandalf"    Display myCat.Sleep()   Display myDog.Sleep()  } 

Running the program will now display this on screen:

Spock is sleeping. Gandalf is taking a nap. 

When you call a method or want to access a property on an object, the computer will look for it within the class that was used to create the object. If it doesn’t find it there, it will look for it in the base class. If it doesn’t find it in the base class, the computer will output an error saying that the member was not found.

That is why, here, when calling Sleep on myCat, the computer looked for the method in the Cat class, didn’t find it but knew that Cat inherited from Animal so it looked for it in Animal, found it and used it. When calling Sleep on myDog, the computer looked for it in the Dog class, found it there and used it without even trying to find a Sleep method in Animal.

Summary

You now know that repeating yourself is not a good practice and that is why we use the DRY principle. The DRY principle can be applied to object-oriented programming by using inheritance. A child class inherits from a base class and thus can access all the members implemented in the base class. Some programmers use the term parent class for a base class. We’ve also seen that a child class can implement members such as methods and properties that are not present in the base class. And we learned that we can override methods from a base class inside a child class; that is provide our own version of a method that already exists in a base class.

Congratulations! You’ve made it through some challenging lessons. The last four lessons on object-oriented programming were heavy on theory. All of this fuzzy theory will soon be put into practice when we learn a real programming language and your efforts will start to pay dividends as you see results on your screen. Keep up the good work!

Important Words

  • DRY principle
  • Inheritance
  • Base class / parent class
  • Child class
  • Override
Exercise

Since we’ve concluded our basic introduction to object-oriented programming, now is the perfect time to assess your understanding. Could you devise a program that would make use of a car, a truck and a motorbike? Write the pseudocode for each class, wrap them in a library and then create the program that would use these classes. Share your code in the Forums, so that your fellow trainee coders (and OptionalBits instructors) can see, comment, and help correct your work.

Share to friends