Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can't Swift initializers call convenience initializers on their superclass?

Consider the two classes:

class A {     var x: Int      init(x: Int) {         self.x = x     }      convenience init() {         self.init(x: 0)     } }  class B: A {     init() {         super.init() // Error: Must call a designated initializer of the superclass 'A'     } } 

I don't see why this isn't allowed. Ultimately, each class's designated initializer is called with any values they need, so why do I need to repeat myself in B's init by specifying a default value for x again, when the convenience init in A will do just fine?

like image 327
Robert Avatar asked Jun 09 '14 14:06

Robert


People also ask

Can we override convenience init Swift?

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 Delegation for Class Types.

What are convenience and required Initializers in Swift explain briefly about them?

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.

Can you override a convenience init?

“If the initializer you are overriding is a convenience initializer, your override must call another designated initializer from its own subclass.”


2 Answers

This is Rule 1 of the "Initializer Chaining" rules as specified in the Swift Programming Guide, which reads:

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

https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/Initialization.html

Emphasis mine. Designated initializers cannot call convenience initializers.

There is a diagram that goes along with the rules to demonstrate what initializer "directions" are allowed:

Initializer Chaining

like image 83
Craig Otis Avatar answered Oct 03 '22 22:10

Craig Otis


Consider

class A {     var a: Int     var b: Int      init (a: Int, b: Int) {         print("Entering A.init(a,b)")         self.a = a; self.b = b     }      convenience init(a: Int) {         print("Entering A.init(a)")         self.init(a: a, b: 0)     }      convenience init() {         print("Entering A.init()")         self.init(a:0)     } }   class B : A {     var c: Int      override init(a: Int, b: Int)     {         print("Entering B.init(a,b)")         self.c = 0; super.init(a: a, b: b)     } }  var b = B() 

Because all designated initializers of class A are overridden, class B will inherit all convenience initializers of A. So executing this will output

Entering A.init() Entering A.init(a:) Entering B.init(a:,b:) Entering A.init(a:,b:) 

Now, if the designated initializer B.init(a:b:) would be allowed to call the base class convenience initializer A.init(a:), this would result in a recursive call to B.init(a:,b:).

like image 43
beba Avatar answered Oct 04 '22 00:10

beba