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:
C2
does not exist,P
is a protocol, and methods are dispatched statically, and althoughbar()
is a requirements ofP
, it is not implemented byC1
which has the conformance toP
so:and that is normal, and interestingly you have:
Meaning that if you only have a reference to
some P
, the subclassC2
ofC1
behaves exactly as it's superclass:call_bar()
callsP.bar()
becauseC1
does not implementbar()
now let's look at what happens if you implement
bar()
inC1
:If we use a reference to
C1
usingsome P
:now in
call_bar()
the compiler knows it has to useC1.bar()
so with a reference toC2
usingsome P
:The subclass
C2
still behaves the same way as it's superclassC1
and it's implementation ofbar()
get's called. (And I find it somewhat reassuring when sublasses behave as their parent).now let's check the original snippet :
it work's !