Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is the superclass designated initializer getting called by default? [duplicate]

I am new to Swift and getting some problem regarding initializers. I have created a Swift file with the following code :

import Foundation

class SuperClass
{
    var a : Int
    init()
    {
        a = 10
        print("In Superclass")
    }
}

class SubClass : SuperClass
{
    override init()
    {
        print("In Subclass")
    }
}

In the above code, init() of SubClass does not contain call to init() of SuperClass i.e. there is no super.init() in SubClass init().

So my question is:

1. Why is it not giving any error if I don't call designated init() of SuperClass

2. If I am creating an object of SubClass i.e. let s = SubClass(), the output is :

In Subclass

In Superclass

Why the init() of SuperClass is getting called? Does a subclass init() calls the superclass init() by default?

like image 223
PGDev Avatar asked Oct 14 '25 07:10

PGDev


2 Answers

As far as I understood your question, you're not only wondering why, when and how the initializer gets called automatically, but also complaining about the missing documentation of this behavior.

First of all I agree with you on the lack of documentation - just like you I'm not able to find anything about this behavior and therefore it should be added to the documentation by Apple.

Why super.init() is called:

As per documentation a designated initializer of the superclass has to be called by a designated initializer of its subclass in order to fully initialize all properties.

Rule 1

A designated initializer must call a designated initializer from its immediate superclass.

Your code example above proves it's obviously done implicitly: print("In Superclass") prints to the console, so super.init() is somehow invoked while creating an instance.

When and how super.init() is called:

There are some conditions to be met in order to allow the compiler to call the designated initializer of the superclass implicitly:

  1. The superclass must have only one designated initializer which is then called. Otherwise the compiler had to choose one to delegate to. This single designated initializer could be also the default initializer or an inherited initializer.

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
        // introduction of a second designated initializer in superclass:
        init(withValue value: Int) {
            a = value
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: super.init isn't called on all paths before returning from initializer"            
        override init() {}
    }
    
  2. The single designated initializer of the superclass mustn't have any parameters. After all the compiler wouldn't know any appropriate parameter to be passed.

    class SuperClass {
        var a: Int
        // declaration of an initializer with parameter:
        init(withValue value: Int) {
            a = value
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: super.init isn't called on all paths before returning from initializer"            
        override init() {}
    }
    
  3. The designated initializer of the subclass mustn't further read or modify (inherited) instance properties of the superclass or call instance methods of the superclass. That's because of Swift's two-phase initialization process with its corresponding safety checks and the fact that the implicit delegation up to the designated initializer of the superclass happens at the end of the init-Statement in the subclass.

    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.“

    Safety check 4

    An initializer cannot call any instance methods, read the values of any instance properties, or refer to self as a value until after the first phase of initialization is complete.

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
    }
    
    class SubClass: SuperClass {
        // won't compile:
        // "error: use of 'self' in property access 'a' before super.init initializes self"            
        override init() {
            a = 10 // modifying inherited self.a before phase 1 of initialization completes isn't valid! 
            // implicit delegation to super.init()
        }
    }
    

    Safety check 1

    A designated initializer must ensure that all of the properties introduced by its class are initialized before it delegates up to a superclass initializer.

    class SuperClass {
        var a: Int
        init() {
            a = 10
        }
    }
    
    class SubClass: SuperClass {
        // introduction of instance property "b"
        var b: Int
        // compiles finely:
        override init() {
            b = 10 // initializing self.b is required before delegation!
            // implicit delegation to super.init()
        }
    }
    

I hope that helps.

like image 79
Tobi Avatar answered Oct 16 '25 21:10

Tobi


Why the init() of SuperClass is getting called? Does a subclass init() calls the superclass init() by default?

Basically, yes.

If all the rules say that you should say super.init() and you don't say it, it is called for you.

I don't like this behavior; it is poorly documented, and besides, secretly doing stuff for you seems against the spirit of Swift. But I filed a bug against it long ago and was told it was intended behavior.

like image 39
matt Avatar answered Oct 16 '25 19:10

matt



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!