Dispatching to Swift protocol extension

Viewed 59

Why does the following code print "BaseP" at #2?

protocol BaseP { func foo() }
extension BaseP { func foo() { print("BaseP") } }
protocol SubP: BaseP {}
extension SubP { func foo() { print("SubP") } }

class C: SubP {}
let subP1: SubP = C()
subP1.foo()   //  #1 prints "SubP", fine.

class BaseC: BaseP {}
class SubC: BaseC, SubP {}
let subP2: SubP = SubC()
subP2.foo()   //  #2 prints "BaseP". why?

    

In both cases we call foo() on a reference with a static type of SubP, referencing an object with a dynamic type that is a class conforming to SubP. Even if it was a static dispatch, I'd think that it should still call SubP.foo(). Why does the base protocol implementation get called at #2?

Also, why does inheriting from BaseC make a difference (if in the class SubC line I remove BaseC or replace it with BaseP, then it suddenly prints "SubP")?

1 Answers

When you call subP1.foo() or subP2.foo(), you are calling the foo that satisfies the protocol requirement foo in BaseP. (i.e. the method that witnessed BaseP.foo). There can be only one such witness.

The other important thing is that the foo requirement is not in SubP, but in BaseP. The only requirement of SubP is that the conformer has to also conform to BaseP.

In the case of subP1, C directly conforms to SubP. To resolve the only requirement of SubP, C has to also conform to BaseP. Now the compiler needs to figure which method can witness foo. There are two methods available, but the one from the SubP extension hides the one from the BaseP extension, so the one from the SubP extension is chosen to be the witness, so you see SubP printed.

In the case of subP2, the witness of foo is already decided when you conformed BaseC to BaseP. Here, there is only one choice - foo from the BaseC extension. When you later conformed SubC to SubP, the only requirement left is that SubC should also conform to BaseP. Well, you said SubC inherits from BaseC, so that's fine. The compiler is happy, and foo from the BaseP extension ends up being the witness.

Related