Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Convenience Init Override

Problem

Override a convenience initializer of a subclass and it produces a compile error.

Detail

I am having issues understanding why Swift (v4.1) is not letting me override my convenience initializer. Reading the documentation I found that these two rules apply to my question:

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.

In the code below I fall under the first rule and all my convenience initializers are inherited into ClassB. Furthermore, since I inherited all the designated initializers as per rule one, I also get all my convenience initializers inherited.

class ClassA<T> {

    // This array would be private and not visible from ClassB
    var array: [T]?

    init() { }

    convenience init(array: [T]) {
        self.init()

        self.array = array
    }
}

class ClassB<T>: ClassA<T> {

    var anotherArray: [T]?

    // I feel like I should include the "override" keyword
    // but I get a compiler error when "override" is added before "convenience init".
    convenience init(array: [T]) {
        self.init()

        self.anotherArray = array
    }
}

// Works fine
let instanceA = ClassA(array: [1, 2])
// Compile error when override is added:
// error: Initializer does not override a designated initializer from its superclass
// note: attempt to override convenience initializer here
//     convenience init(array: [T]) {
//                 ^
let instanceB = ClassB(array: [1, 2])

But here is what I don't understand: ClassB has a slightly different implementation of init(array:) and I would like to override that convenience initializer. Using the override keyword produces a compile error. Am I understanding these initialization concepts wrongly?

like image 762
Jad Avatar asked Aug 15 '14 06:08

Jad


People also ask

Can you override a convenience init?

It's not illogical to override a convenience initializer. Instead, it's unsafe to override a convenience initializer — in the context of all the other rules about designated and convenience initializers, and the two-passes of initializations, and order in which initialization occurs.

What is a convenience init?

convenience init : Convenience initializers are secondary, supporting initializers for a class. You can define a convenience initializer to call a designated initializer from the same class as the convenience initializer with some of the designated initializer's parameters set to default values.

What is override init?

Overriding init()Override the class initializer init() to initialize or allocate resources for the servlet instance's life, such as a counter. The init() method runs after the servlet is instantiated but before it accepts any requests.

What does init () do in Swift?

Swift init() Initialization is the process of preparing an instance of a class, structure, or enumeration for use. This process involves setting an initial value for each stored property on that instance and performing any other setup or initialization that is required before the new instance is ready for use.


1 Answers

The reason override is unneeded:

Conversely, if you write a subclass initializer that matches a superclass convenience initializer, that superclass convenience initializer can never be called directly by your subclass, as per the rules described above in Initializer Chaining. Therefore, your subclass is not (strictly speaking) providing an override of the superclass initializer. As a result, you do not write the override modifier when providing a matching implementation of a superclass convenience initializer.

But as written, it seems it should work — as far as I can tell this is a compiler bug. If you change the name of the array argument to ClassB's initializer to e.g. array2, then it works as expected. You should file a Radar!

like image 130
jtbandes Avatar answered Oct 04 '22 04:10

jtbandes