Why can't we add designated initialisers in extensions in swift?
Asked Answered
P

2

15

The only difference I can see between designated and convenience initialisers is that the former necessarily calls a super class init (if available).

I don't understand then why I can't add a designated init to a class in an extension, while adding a convenience one is OK.

Why is it so bad to have an init from an extension to possibly call a super class initialiser?

Plasia answered 12/11, 2014 at 0:44 Comment(0)
A
25

Let's recall what a designated initializer is.

A designated initializer fully initializes all properties introduced by that class and calls an appropriate superclass initializer to continue the initialization process up the superclass chain.

Excerpt From: Apple Inc. “The Swift Programming Language.”

class ClassA {
        private let propertyA: Int

        init(propertyA: Int) {
                self.propertyA = propertyA
        }
}

class ClassB: ClassA {
        private let propertyB: Int

        init(propertyA: Int, propertyB: Int) {
                self.propertyB = propertyB
                super.init(propertyA: propertyA)
        }
}

extension ClassB {
        // If this was a designated initializer, you need to initialize propertyB before calling a superclass initializer.
        // But propertyB is a private property that you can't access.
        // If you don't have the source code of ClassB, you will not even know there is a property called propertyB.
        // This is why we can't use extensions to add designated initializers.
        init(propertyC: Int) {
                ...
        }
}
Aggrieve answered 12/11, 2014 at 3:34 Comment(0)
D
0

I am writing from 2023 so maybe there are some changes. So, we have access for private let propertyB in extension ClassB. So go search more, but for me question is still actives

Edited with new information:

The is better example. Imagine we have

class Shape {
    var backgroundColor: UIColor?
    
    init(backgroundColor: UIColor?) {
        self.backgroundColor = backgroundColor
    }
}

class Rectangle: Shape {
    
    var width: Int = 0
    var height: Int = 0
}

As Rectangle does not have any initializers, it inherits the init(backgroundColor:) from the Shape and can be instantiated as below:

let rectangle = Rectangle(backgroundColor: UIColor.green)

Now imagine we could add designated initializers by extensions like this:

extension Rectangle {
    init(backgroundColor: UIColor?, width: Int, height: Int) {
        self.width = width
        self.height = height
        super.init(backgroundColor: backgroundColor)
    }
}

From now on, the Rectangle class Will have a designated initializer for its own, hence, the Swift will remove the inherited initializer init(backgroundColor:) from the Rectangle. So what will happened to the codes that used the inherited initializer to instantiate the Rectangle. All of them would be invalid. Now suppose the Shape and Rectangles are classes that have been defined in one of the Apple frameworks. Good job. We managed to make Apple frameworks invalid. Therefore, it is reasonable that Swift does not allow us add designated initializers using the extensions.

There question is still Active:

We can add designated init for Struct. And it will destroy default memberwise initializer.

Silly example:

struct FirstStruct {
    var prop1: Int
    private var prop2: Int
}

extension FirstStruct {
    init(prop: Int) {
        self.prop1 = prop
        self.prop2 = prop
    }
}

Now FirstStruct does not have FirstStruct(prop1: Int, prop2: Int) initialiser.

Dentelle answered 15/7, 2023 at 13:14 Comment(7)
"So, we have access for private let propertyB in extension ClassB." Only in the same file. This doesn't significantly change the situation. Your second section captures the point of why functions can never be removed (and is a good example of why extensions must only add, not attempt to change, methods), though there is no reason that allowing designated init in the same file via extension would cause inherited init to be deleted. In your third example, the init is not deleted. It never existed because prop2 is private. (Remove the extension and try to use it.)Oration
@RobNapier ok lets go by one. Maybe I am not so strong. 1) Only in the same file. - its true, i don't even know this about.Dentelle
@RobNapier ok lets go by one. Maybe I am not so strong. 1) Only in the same file. - its true, i don't even know this about. 2) Don't understand about add functionality. When I add new init I add functionality and not change it. 3) What do you mean about it never existed. I tried same things with 'struct'. Move to other file. So in 'struct' i can create new init, and memberwise will disappear. I created new designated init in extension but only init one property because i don't se private one, the compiler tell me "not all stored properties was initialised" why it does not work in class?Dentelle
(2) I was saying that you've made a good explanation of why extensions can only add functionality, not change or remove it (i.e. other parts of the program may rely on the original implementation). I agree that the added init is just added functionality. But the reason for disallowing it just isn't related to your discussion in your second section.Oration
(3) Creating an init in an extension does not remove the auto-generated one. In your emplate there was no auto-generated one because prop2 is private (it doesn't auto-gen in that case). Structs never have designated inits. "Designated" is only for inheritance. docs.swift.org/swift-book/documentation/… (And for more, I highly recommend the whole page)Oration
Got it, problem is that i did not find in Swift documentation about not auto-generated init with private properties. Maybe i am bad reader. But a question is still active: Why we can add Designated ( lets say like this i mean main init not a convenience ) init to extension in Struct and not in Class.Dentelle
There is no such thing as a designated or convenience init for struct. The sentence I was really pointing to was "Designated initializers are the primary initializers for a class." The whole concept of "designated" is about inheritance, and structs have no inheritance. So yes, you can have an init in a struct extension as long as it is in a place that can access all the properties, or some other init.Oration

© 2022 - 2024 — McMap. All rights reserved.