Please consider the following Swift 5 code:
protocol P: class {
    func call_foo()
    func foo()
    func call_bar()
    func bar()
}
extension P {
    func call_foo() { foo() }
    func foo() { print("P.foo") }
    func call_bar() { bar() }
    func bar() { print("P.bar") }
}
class C1: P {
    func foo() { print("C1.foo") }
}
class C2: C1 {
    func bar() { print("C2.bar") }
}
let c = C2()
c.call_foo()    //  C1.foo
c.foo()         //  C1.foo
c.call_bar()    //  P.bar
c.bar()         //  C2.bar
If the foo() call in P.call_foo() gets dynamically dispatched to C1.foo(), then why the bar() call in P.call_bar() does not get dynamically dispatched to C2.bar()?
The only difference is that foo() is overridden directly in the class that conforms to P, and bar() is only overridden in a subclass. Why does that make a difference?
Given that bar() is a protocol requirement, shouldn't all calls to it always get dynamically dispatched?
In the context of your extension:
extension P {
    func call_foo() { foo() }
    func foo() { print("P.foo") }
    func call_bar() { bar() }
    func bar() { print("P.bar") }
}
C2 does not exist, P is a protocol, and methods are dispatched statically, and although bar() is a requirements of P, it is not implemented by C1 which has the conformance to P so:
let c1: some P = C1()
c1.call_foo()    //  C1.foo
c1.foo()         //  C1.foo
c1.call_bar()    //  P.bar
c1.bar()         //  P.bar
and that is normal, and interestingly you have:
let someP: some P = C2()
someP.call_foo()    //  C1.foo
someP.foo()         //  C1.foo
someP.call_bar()    //  P.bar
someP.bar()         //  P.bar
Meaning that if you only have a reference to some P, the subclass C2 of C1 behaves exactly as it's superclass: call_bar() calls P.bar() because C1 does not implement bar()
now let's look at what happens if you implement bar() in C1:
class C1: P {
    func foo() { print("C1.foo") }
    func bar() { print("C1.bar") }
}
class C2: C1 {
    override func bar() { print("C2.bar") }
}
If we use a reference to C1 using some P:
let c1: some P = C1()
c1.call_foo()    //  C1.foo
c1.foo()         //  C1.foo
c1.call_bar()    //  C1.bar
c1.bar()         //  C1.bar
now in call_bar() the compiler knows it has to use C1.bar() so with a reference to C2 using some P:
let someP: some P = C2()
someP.call_foo()    //  C1.foo
someP.foo()         //  C1.foo
someP.call_bar()    //  C2.bar
someP.bar()         //  C2.bar
The subclass C2 still behaves the same way as it's superclass C1 and it's implementation of bar() get's called. (And I find it somewhat reassuring when sublasses behave as their parent).
now let's check the original snippet :
let c = C2()
c.call_foo()    //  C1.foo
c.foo()         //  C1.foo
c.call_bar()    //  C2.bar
c.bar()         //  C2.bar
it work's !
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With