34

If I have a swift subclass that:

  1. doesn't need to access self
  2. doesn't need to access any properties on self

Do I still have to call super.init() in the subclass's init() method?

*Note: This is a different question than the one asked and answered here on SO because of the specifics listed in 1 and 2 above.

Community
  • 1
  • 1
bearMountain
  • 3,950
  • 1
  • 36
  • 44

4 Answers4

30

No, you don't have to.

Assume you have the following classes.

class a {
    let name: String

    init() {
        name = "james"
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
    }
}

If you instantiate a variable with

let myVar = b()

Then,

  • override init() in b will be called
  • then the init() in a will be called

Even though you didn't explicitly call super.init().


This has been confirmed by Chris Laettner on the swift-user's email list. It kicks in when your super class has a single designated initializer with a zero-argument init. This is why you don’t have to call super.init() when deriving from NSObject.

*Thanks to Wingzero's comment below

bearMountain
  • 3,950
  • 1
  • 36
  • 44
  • Shouldn't super.init be called *before* the override? – Joe Aug 12 '14 at 06:36
  • 1
    No, swift initialization differs from Objective-C initialization. It is no longer standard to call `[super init]` before you perform you initializations. https://developer.apple.com/library/prerelease/ios/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html – bearMountain Aug 12 '14 at 06:57
  • From that page "Once the superclass’s designated initializer is finished, the subclass’s designated initializer can perform additional customization (although again, it does not have to)." – Joe Aug 12 '14 at 07:43
  • You can think of it as a 3-step process: (1) initialize new instance vars of the subclass, (2) call super.init, (3) any further activity (can include method calls, etc.). If you don't need step three, Swift can take of step 2 for you. – Nate Cook Aug 13 '14 at 01:12
  • "then the init() in a will be called" do you have any citation for this? – newacct Aug 13 '14 at 05:18
  • 1
    @newacct see Viktor Lexington's answer above for the exact citation. My answer explains it in more practical terms. Essentially the super init will be called. If you don't have an init, it will inherit. If you do have an init, then either you call super yourself inside it, or it'll be called automatically at the end of your init. – Rikkles Aug 13 '14 at 07:02
  • @Rikkles: I don't think Viktor Lexington's citation is relevant to this at all. "Essentially..." Is that just a guess? I don't see this being supported by the documentation. – newacct Aug 13 '14 at 08:07
  • This works for me. But I can not find any citation for it. Anyone can find some documents? – migrant Feb 13 '16 at 11:34
  • 2
    Father of Swift confirmed it: https://lists.swift.org/pipermail/swift-users/Week-of-Mon-20160516/001930.html: This is intentional behavior. It kicks in when your super class has a single designated initializer with a zero-argument init. This is why you don’t have to call super.init() when deriving from NSObject. – Wingzero Sep 28 '16 at 02:23
13

From the docs:

Designated initializers must call a designated initializer from their immediate superclass.

Also, regarding automatic initializer inheritance:

Assuming that you provide default values for any new properties you introduce in a subclass, the following two rules apply:

Rule 1 If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.

Rule 2 If your subclass provides an implementation of all of its superclass designated initializers—either by inheriting them as per rule 1, or by providing a custom implementation as part of its definition—then it automatically inherits all of the superclass convenience initializers.

These rules apply even if your subclass adds further convenience initializers.

So the answer to your question is as follows:

Your subclass will always call a designated initializer of your superclass. If you don't write an initializer and the compiler doesn't complain, then it has used automatic initializer inheritance. And if you do write an initializer but it doesn't explicitly call a relevant upstream (or sidestream) initializer, it will be done for you automatically at the end of your initializer.

Furthermore, the way chained initializers work is in a 2-phase process. In the first phase, it starts from the subclasses towards superclasses, assigning default values to any parameters. In the second phase, the process is run backwards, starting with superclasses and ending with your subclass, where the customization of parameters is done and overridden.

This means that you must absolutely first in each init() set your variables, and then you're free to call (or not) the super.init() and run custom code. So as you asked above, if you want the super's init to run at the beginning, consider the 'beginning' to be just after your creating your variables:

class a {
    var name: String

    init() {
        name = "james"
        println("a")
    }
}

class b: a {
    let title: String

    override init() {
        title = "supervisor"
        super.init()
        self.name = "john"
        println("b")
    }
}

let x = b()

This will print a, then b.

Rikkles
  • 3,372
  • 1
  • 18
  • 24
  • 2
    "If you don't do it yourself and the compiler doesn't complain, then it has used automatic initializer inheritance." Automatic initializer inheritance is about inheriting designated initializers if you don't have any designated initializers, or inheriting convenience initializers if you override all superclass's designated initializers. I don't see how it is related to implicitly calling super's initializer. – newacct Aug 13 '14 at 05:20
  • `Rule 1: If your subclass doesn’t define any designated initializers, it automatically inherits all of its superclass designated initializers.` What I mean by that is that there is no way that you can **avoid** calling a superclass's initializer. And that was the question asked. – Rikkles Aug 13 '14 at 06:53
  • I see what you mean, I just updated my answer with a more specific explanation. Thanks. – Rikkles Aug 13 '14 at 06:59
  • 2
    I take "Designated initializers must call a designated initializer from their immediate superclass." to mean that it's not possible to not explicitly call the superclass designated initializer. "And if you do write an initializer but it doesn't explicitly call a relevant upstream (or sidestream) initializer, it will be done for you automatically at the end of your initializer." I don't see that documented anywhere. – newacct Aug 13 '14 at 08:06
5

Yes the designated initializer need to delegate up, so it must call the super.init(). If you don't write the line, the compiler will do it for you.

So you do not have to explicitly write super.init(...), but the subclass has to, even if only behind the curtain.

But remember, in the first phase you need to set the properties in the subclass, then the super.init() must be called. In the second phase you may change all the inherited properties. I think super.init() is a perfect separator between phase 1 and phase 2.

From the docs:

Safety check 2

A designated initializer must delegate up to a superclass initializer before assigning a value to an inherited property. If it doesn’t, the new value the designated initializer assigns will be overwritten by the superclass as part of its own initialization.

Community
  • 1
  • 1
Binarian
  • 12,296
  • 8
  • 53
  • 84
  • 1
    I don't think that quote is relevant. From how I read it, the "it" refers to the "before assigning a value to an inherited property". So "If it doesn't" = "if you assign a value to an inherited property before calling the superclass initializer". This makes perfect sense because then of course when the superclass initializer will overwrite it. But it doesn't have anything to do with not calling a superclass initializer. – newacct Aug 13 '14 at 08:03
  • @newacct The idea of the second bold line in the quoted text was that if you don't write `super.init()` *I thought* it could be that the compiler sets it after setting *all* the properties, that means none of you inherited properties would be set with the new values. To make sure everything works, I will write `super.init()` myself, between setting the added properties and setting the inherited properties. (I didn't try it extensively, so maybe the compiler is perfect in that regard) – Binarian Aug 13 '14 at 09:15
0

I think you don't have to call super. I tried to simulate situation as follow:

class Animal {
}

class Parrot: Animal {

    override init() {
        // Some code (super not called)
    }
}

However, i would recommend to always call super.init in real app, like you use to do in Objective-C.

Evgeniy Kleban
  • 6,794
  • 13
  • 54
  • 107
  • If you don't call `super.init()` explicitly, it will be called automatically at the end of the sub classes `init()`. You can verify this by dropping a `init() { fatalError() }` in your base class. – Andres Canella Jul 09 '22 at 00:25