Calling a protocol extension initializer

2.6k Views Asked by At

I'm trying to build a set of classes that would share common initializing code. Apart from inheritance, I thought protocols would be the way to go. While protocols and protocol extensions worked for me with instance and static methods, I have some troubles making it work with initializers.

Let's say we have this protocol:

protocol CloudServiceWrapper {

    static var isConfigured: Bool { get }

    init()

    func initialize()

}

Now let's say we want to add default implementations for both isConfigured and init() in a protocol extension:

extension CloudServiceWrapper {

    static var isConfigured: Bool {
        get {
            return true
        }
    }

    init() {
        print("Initializing generic CloudServiceWrapper")
        self.init()
        if Self.isConfigured {
            initialize()
        }

    }

}

Finally, let's have a class implementing this protocol and trying to benefit from its default implementations:

class OneDriveWrapper: CloudServiceWrapper {

    required init() {
        // CloudServiceWrapper() // error: protocol type 'CloudServiceWrapper' cannot be instantiated
        // self = CloudServiceWrapper.init() // error: cannot assign to value: 'self' is immutable
        // super.init() // error: 'super' members cannot be referenced in a root class
        // (self as CloudServiceWrapper).init() // error: static member 'init' cannot be used on instance of type 'CloudServiceWrapper'
        print("Initializing OneDriveWrapper")
    }

    func initialize() {
        print("Done")
    }

}

When trying to build a new instance of the OneDriveWrapper class, there's simply no way I could find to both call the class' initializer, and the default protocol implementation. And it is not possible to omit the init() in the OneDriveWrapper class, since it is required per the protocol definition, and seemingly not considered "implemented" with the protocol extension.

In fact, more broadly, I couldn't find any way to explicitly call a protocol extension's initializer, even though I know it's possible for instance methods.

What am I doing wrong? Do you know any way of combining both the class' initialiser and the protocol extension's one? Should I fall back to class inheritance instead of protocols and extensions?

Thanks!

3

There are 3 best solutions below

1
On BEST ANSWER

An init within a protocol is required, and therefore has to be implemented explicitly i.e. a default implementation cannot be utilised.

As for 'explicitly calling a protocol extension's initializer', you cannot instantiate a protocol type.

I would suggest using inheritance for this.

7
On

This answer is not pointing out the core issue of the OP. Kept here just for a record.


You are doing completely wrong. Protocol is not superclass.

Default implementation of protocol is just a default used when you do not implement a protocol required method. You cannot call default implementations of a protocol directly by any means.

Protocol is not a simple replacement of superclass. Change your way of thinking based on the protocol.

even though I know it's possible for instance methods.

You are mistaking something. You cannot call protocol's default implementation even if it's a method.

0
On

Public default init in protocol is a similar question.

Why does a class require having an init despite the protocol providing a default implementation? The answer is that it isn‘t providing a default implementation, but rather just another init, which requires the class‘ init() here to exist.

Since your protocol can't be certain to cover all members of the class that uses it, any initializer you declare in your protocol will need to delegate initialization of the "unknown" members of the class to another initializer provided by the class itself. Source

Your protocol init is however probably shadowed by the class‘ init() so you won‘t be able to use it. Maybe add a parameter to the class initializer/the protocol‘s required initializer or a parameter to the protocol-extension ìnit(). If the protocol-extension init isn‘t shadowed by the class you will be able to use it to init the class.

The init is required because the class can be subclassed and initializer aren‘t necessarily inherited, see inheritance doc and initialization doc under Initializer Inheritance and Overriding on this. If the init weren‘t required a subclass wouldn‘t be adhering to the protocol anymore, which is undesirable and so the init set in a protocol is only fullfiled by a required initializer.

Note: In required init() you tried to call another initializer but I think this is not possible except for initializing a parent since required init() is a designated initializer which cannot be chained in the same class, only convenience initializers can be chained in the same class.

You can see the protocol-extension ìnit as a convenience initializer because the init requires calling another initializer, like every other convenience initializer does with self.init(...).