Skip to content
Theory · Classes · lesson 7 of 10

Subclass initializers and final

Imagine an animal's card at a vet clinic. The front desk writes the name on it, and every animal has that field. A parrot also has a field of its own: how many words it knows. You fill it in, and you do it before handing the card to the front desk. From there the card goes straight to the vet, and the vet may look at any field.

Dog from the lesson on inheritance managed without its own init: it got init(name:) from Animal. That won't work for a parrot. It has its own property words without a default value, and the parent's init(name:) knows nothing about it.

Its own init and super.init

If a subclass has its own property without a default value, it needs its own init. There you first set your own properties and then call super.init, so that the parent sets its own:

SWIFT
class Animal {
    var name: String
    init(name: String) {
        self.name = name
    }
}
class Parrot: Animal {
    var words: Int
    init(name: String, words: Int) {
        self.words = words
        super.init(name: name)
    }
}
let kesha = Parrot(name: "Kesha", words: 20)
print(kesha.name, kesha.words) // Kesha 20

Let's go through the program:

  1. var words: Int is a property of Parrot itself, and it has no default value.
  2. init(name: String, words: Int) takes two values: the name for the parent and the number of words for itself.
  3. self.words = words sets the property of Parrot — the parrot's field on the card.
  4. super.init(name: name) calls the parent's init, and the parent sets name — the name the front desk writes in.
  5. print prints Kesha 20: the parrot has both the inherited property name and its own words.

With its own init, Parrot no longer inherits init(name:). The call Parrot(name: "Kesha") does not compile, because it lacks words:

TEXT
error: missing argument for parameter 'words' in call

Why your own properties come first

Swift requires every property of the subclass to have a value by the time super.init is called. The reason lies in what the parent may do.

Once it has set its own properties, the parent's init may call a method of the instance, for example speak(). If Parrot overrides that method, the Parrot version runs: the version is chosen by the class of the instance itself. And if it reads words, the value must already be there. This is the vet who may look at any field of the card. The order is required always, even when the parent calls no methods at all.

Here the clinic picture falls short. The front desk asks for the name itself, but in Swift the subclass passes it on: super.init(name: name) hands the parent the name parameter that the parrot's init received.

No inheritance: final

The word final forbids inheriting and overriding:

  • a final class cannot be inherited from;
  • a final func method cannot be overridden in a subclass.

This is how the author of a class protects it from changes they did not plan for. For example, if you declare final class Parrot: Animal, the line class Macaw: Parrot {} does not compile:

TEXT
error: inheritance from a final class 'Parrot'

Interviewers also ask about final and speed. Without it, the method's version is chosen while the program runs, by the class of the instance. A subclass cannot write its own version of a final method, so the compiler can call it directly, without that choice.

Common mistake

The subclass init calls super.init first and sets its own property afterwards:

SWIFT
class Cat: Animal {
    var lives: Int
    init(name: String, lives: Int) {
        super.init(name: name) // ✗
        self.lives = lives
    }
}
TEXT
error: property 'self.lives' not initialized at super.init call

The program does not compile: when super.init is called, lives has no value yet. Swap the two lines: first self.lives = lives, then super.init(name: name).

Key points

  • A subclass init first sets its own properties, then calls super.init; in the reverse order the program does not compile.
  • The order matters because the parent's init may call an overridden method, and that method may read a subclass property.
  • A subclass with its own init does not inherit the parent's init: Parrot(name: "Kesha") does not compile.
  • A final class cannot be inherited from, and a final func cannot be overridden.