According to what I understood about dispatch in protocols here (correct me if I am wrong) is..... swift bypasses the greet method declared in struct when greeter.greet method is called first.This is because the extension protocol gets replaced inside the protocol witness table.
In second function call, it prints bye rather than Tshcuus. Clearly, leave method from extension is printed. I read the explanation why does this happen but I am not confident much if I understand this completely.
Kindly Explain briefly.
Because the variable is declared as Greetable
, and leave
is not a requirement for the protocol.
Maybe it helps to think of the situation this way:
The compiler knows that the object — no matter what type it actually has — has a greet-method; either a custom one, or the default implementation from the protocol as a fallback.
For leave
on the other hand, it is only clear that there is an implementation from the protocol, so that is called.
Wouldn't it be possible to call the custom implementation anyways?
Technically, probably yes... but it would be more brittle:
Methods can be declared in many different places (and modules). For example, what should happen if there is a second leave
supplied by another protocol the type conforms to? Should that also be preferred over the method from the "right" protocol, which hopefully designed its methods so that they make sense in combination?
The difference here is whether the method is declared in the main body of the protocol or not (the actual protocol Greetable
declaration. Members listed there (such as greet
) are called "requirements", and you can provide implementations for them in extensions, which are known as "default implementations."
Somewhat confusingly, you can also define other members in protocol extensions. I'm not sure there's a super solid consensus around what to call these members, though the common terminology seems to be "extension methods" or "extension members."
I say "confusingly" because as you've noted, despite the fact that Greetable.greet
and Greetable.leave
look very similar at the point where they are implemented, their behavior can differ significantly when being called.
When a type conforms to a protocol, it must provide implementations for all of the protocol requirements, which establishes a correspondence between, e.g., GermanGreeter.greet
and the Greeter.greet
requirement. Thus, when you have a value of type GermanGreeter
and store it in a variable of type Greetable
, that correspondence is maintained and allows the Greetable
variable to call the GermanGreeter.greet
implementation when you call greeter.greet()
above.
However, since leave
is not a protocol requirement, no such correspondence is established between Greetable.leave
and GermanGreeter.leave
—as far as Swift is concerned, these are two completely different methods that happen to share the same name (the technical term for this is "shadowing"). Thus, when you have a variable of type Greetable
, the compiler can only find the Greetable.leave
declaration, since GermanGreeter.leave
is completely unrelated. The correspondence that was maintained between GermanGreeter.greet
and Greetable.greet
above doesn't apply, since Greetable.leave
isn't a requirement.