Here is a code snippet to narrow down the problem:
import Foundation
protocol SampleProtocol {
func foo()
}
extension SampleProtocol {
func foo() {
print("protocol foo")
}
func bar() {
print("protocol bar")
}
}
class SampleClass: SampleProtocol {
func foo() {
print("class foo")
}
func bar() {
print("class bar")
}
}
let sample: SampleProtocol = SampleClass()
sample.foo()
sample.bar()
The output is
class foo
protocol bar
But why does it work this way? Why does protocol extension have no impact on SampleClass
? My expectation was to have
class foo
class bar
output
Despite being syntactically similar, foo
and bar
in the protocol extension are semantically very different.
Since the signature of foo
in the extension matches the protocol requirement foo
, it is a default implementation of foo
. When you call sample.foo()
, the default implementation is not called because SampleClass
has its own implementation of foo
.
On the other hand, bar
in the extension does not match any protocol requirements, so it is just a plain old regular method you added to the protocol. It is also not a protocol requirement, which can only be declared inside the protocol declaration itself. It is similar to a regular old global function like this:
func bar(_ `self`: any SampleProtocol) {
print("protocol bar")
}
SampleClass.bar
is totally unrelated to the bar
in the protocol extension. Naturally, sample.bar()
resolves to the bar
in the protocol extension, not SampleClass.bar
, because sample
of type SampleProtocol
at compile time.