Chapter 11: Inheritance

In programming, inheritance isn't at all about randomly gaining a large sum of money from a long-lost relative but understanding what it means is worth much more... Possibly.


What you will learn

  • What is Inheritance?
  • Creating a Parent Class
  • Creating a Child Class
  • Overriding functions from a Parent Class

Key Terms

  • Inheritance: a term to describe when a class is based on another class and inherits its default variables and function implementations.
  • Parent Class: a code template with default values for variables and default implementations for functions.
  • Child Class: a copy of a parent class with the ability to override or modify default parent class implementations and values.

In this chapter, you will read about inheritance. No, not the kind where a wealthy relative passes away leaving you with a huge lump of cash and you quit your job and run away to Bali for a permanent vacation. We're talking about inheritance as in inheriting features or traits as in genetics.

We will talk more about this in a moment, but let's dive into the code first.

Creating a Parent Class

First, open Xcode if you haven't already and click Create New Playground. Give it a name like Inheritance and click Next. Choose somewhere to save this .playground file and click Create to save it. You should see a screen like the one in Figure 1.11.1.

Figure 1.11.1 Screen Shot 2016-10-10 at 5.01.11 AM.png

Delete all the boilerplate code on the left side but leave import UIKit as it is necessary.

What is Inheritance, really?

In iOS development, inheritance is a feature of Object-Oriented Programming which you learned about in the previous chapter on Classes. Classes can inherit traits from other classes which makes it very useful. Think of this all in regards to a family. In every family, there are parents and children. The parents have certain traits which get passed down to the children.

For instance, my hair is brown and my dad's hair is brown. I received that trait from him. There are a number of other traits that are the same between the two of us, but I am different from my dad in a number of ways. While much of me is similar, I have certain skills and traits that are not like my dad.

In Swift, we will create a class to act as a parent class. It will contain many general traits. Then we will create a child class which will inherit traits from the parent class. The child class will have the same traits as it's parent but we can add in special traits unique to the child class alone. But let's start by building our parent class.

Building a Parent Class

While we could create a class about our actual parents and make this a sort of code-based genetics experiment, we are going to do something even cooler – think about super awesome cars! 🚗🚕🚙

Writing a Parent Class

In your Playground window, add the following Vehicle class and create a few variables for things that all vehicles have in common:

class Vehicle {
    var wheels = 4
    var make: String?
    var model: String?
    var currentSpeed: Double = 0
}

Every car has 4 wheels, which is why we created that variable. But why have we not given a value for the make or model of our car? Well, every car has a make and model of some kind, so we actually don't need to specify these properties in our parent class.

Adding some functions

Inside of our Vehicle class, we can actually create some functions that all cars will do also:

class Vehicle {
    var wheels = 4
    var make: String?
    var model: String?
    var currentSpeed: Double = 0

    func drive(speedIncrease: Double) {
        currentSpeed += speedIncrease
    }

    func brake() {
        currentSpeed = 0
    }
}

The functions above may not be the best way to actually perform the driving and braking of a car, but you get the idea – you can add functions to a parent class.

Now let's see inheritance in action – with a child class.

Creating a Child Class

We will create a child class (or subclass) called SportsCar that inherits from Vehicle. This means that it will inherit all the properties and functions inside the Vehicle class unless we change them.

Writing A Child Class

Add the following code beneath the Vehicle class:

...

class SportsCar: Vehicle {

}

What we're doing above is declaring a class called SportsCar and using a colon : to identify that we want to inherit from another class (in this case – Vehicle).

If you're a visual learner, hopefully Figure 1.11.2 can help explain what's going on:

Figure 1.11.2

inheritance-sportscar-only.png

As our class currently stands, it is a clone of the class Vehicle. Everything will be implemented exactly the same way as Vehicle, unless we tell it to do otherwise. That is exactly what we will do now!

Before we can do anything with our SportsCar class we actually need to go back and add an initializer function to our Vehicle class.

Adding an Initializer function in the Vehicle Class

Inside of the Vehicle class, add the following init() function:

class Vehicle {
    var wheels = 4
    var make: String?
    var model: String?
    var currentSpeed: Double = 0

    init() {

    }

    func drive(speedIncrease: Double) {
        currentSpeed += speedIncrease * 2
    }

    func brake() {
        currentSpeed = 0
    }
}

This will give us access to the properties in Vehicle later on when we want to specify them in our SportsCar class.

We can actually do that now by overriding the init() function in the class SportsCar.

Overriding functions from Vehicle

Add the following code to SportsCar:

class SportsCar: Vehicle {
    override init() {
        super.init()
        make = "Lotus"
        model = "Elise"
    }
}

By overriding init() from the Vehicle class, we are able to change how we use it in our SportsCar class. By using super.init() we actually are calling the function from within Vehicle. Because of this we are able to initialize make and model giving them a combined value of "Lotus Elise".

Great, so our fancy-pants sports car has a name now, but we should also think about how it drives. A sportscar drives differently than, say, a minivan, right? So we should override the drive(speedIncrease:) function, too. Try this out in the SportsCar class:

class SportsCar: Vehicle {
    override init() {
        super.init()
        make = "Lotus"
        model = "Elise"
    }

    override func drive(speedIncrease: Double) {
        currentSpeed += speedIncrease * 4
    }
}

We have overridden the function drive(speedIncrease:) so that the amount currentSpeed is increased by, is much faster since a sports car should drive faster than a regular car.

Creating a Sibling Class

If we continue with the example of classes being like a family, creating another class from the parent class results in another child class and we can actually call it a sibling class in relation to the other child classes.

Let's create a child class for another type of car – the minivan. I'm fairly certain that anyone without children reading this just shuddered at the sight of that word – minivan. Sorry about that.

Aside from being an icon of the classical American family, the minivan is very different from a sports car and therefore will need to have different information inside it's class. Let's make it.

Writing another Child Class

In your Playground, add a Minivan class, inheriting from Vehicle beneath the SportsCar class:

...

class Minivan: Vehicle {

}

Here's what we just did for all the visual learners reading this (Figure 1.11.3):

Figure 1.11.3

Inheritance-no-lotus.png

Overriding functions from the Parent Class

If we want to add in a custom make and model value, we need to override the init() function from Vehicle just like before. Add the following code to Minivan:

class Minivan: Vehicle {
    override init() {
        super.init()
        make = "Chevrolet"
        model = "Astro"
    }
}

We've now initialized the variables make and model and given them the values for a Chevrolet Astro (ah, childhood).

What we should do now is override the drive(speedIncrease:) function to change how our minivan drives. Anyone who's ever driven in or driven behind a minivan knows that they aren't the quickest vehicles in the world – especially if loaded up with all the kids.

Inside of the Minivan class, override drive(speedIncrease:) like so:

class Minivan: Vehicle {
    override init() {
        super.init()
        make = "Chevrolet"
        model = "Astro"
    }

    override func drive(speedIncrease: Double) {
        currentSpeed += speedIncrease
    }
}

Wrapping up

Why does this matter? It allows us to compartmentalize our code and adapt it to meet specific needs.

In closing, here's a real-life example from Instagram. For creating their filters, Instagram may have used a parent class including a generic filter. But each individual filter (i.e. Valencia, Inkwell, Nashville, etc.) could have been made into a child class containing a unique algorithm for filtering a photo a certain way.

Rather than putting all filters in one gigantic class, child classes could have been used to make a much more readable and compact code base.

Inheritance is a foundational principle of Object-Oriented Programming and is super important to understand if you want to be a professional programmer. Remember that this chapter is not exhaustive. There are endless resources online to help in understanding this. Never stop learning and seeking understanding.

Exercise

Create a class for a Pickup Truck that inherits from Vehicle. Override the initializer and set the make and model properties to fit the truck. Override the drive(speedIncrease:_) function so that the car can drive half as fast as the SportsCar.

In the Vehicle class, add a property of type Bool called hasStorageSpace but don't initialize it yet. Initialize that property in the classes which do or don't have storage space using true or false.