swiftprotocol-extension

How to invoke protocol extension default implementation with type constraints


Consider the following example:

class ManObj {
    func baseFunc() {
        print("ManObj baseFunc")
    }
}

class SubObj: ManObj {
}

protocol Model {
}

extension Model { // This is protocol extension
    func someFunc() { // Protocol extension default implementation
        (self as! ManObj).baseFunc()
        print("Model implementation")
    }
}
extension SubObj: Model {
    func someFunc() {
        print("SubObj Implementation")
    }
}

let list = SubObj()
list.someFunc() // static dispatching

let list2: Model = SubObj()
list2.someFunc() // dynamic dispatching

The output is nicely:

SubObj Implementation
ManObj baseFunc
Model implementation

But I dislike the casting in the line (self as! ManObj).baseFunc().

In fact, I only plan to apply Model protocol to subclasses of ManObj. (But not all subclasses of ManObj are Model though!) So, I tried to change Model to:

extension Model where Self: ManObj {
    func someFunc() {
        self.baseFunc() // No more casting needed!
        print("Model implementation")
    }
}

But I'm greeted with error:

list2.someFunc() <- error: 'Model' is not a subtype of 'ManObj'

So, is there a way for me to trigger Model.someFunc from list2 after I constrain Model to where Self: ManObj?


Solution

  • Create an empty class just for type casting

    class ManObj {
        func baseFunc() {
            print("ManObj baseFunc")
        }
    }
    
    class SubObj: ModelCaster {
        func someFunc() {
            print("SubObj Implementation")
        }
    }
    
    protocol Model {
    }
    
    extension Model where Self: ModelCaster { // This is protocol extension
        func someFunc() { // Protocol extension default implementation
            print("Model implementation")
        }
    }
    
    class ModelCaster: ManObj, Model{
    
    }
    
    let list = SubObj()
    list.someFunc() //SubObj Implementation
    
    let list2: ModelCaster = SubObj()
    list2.someFunc() //Model implementation