Confused by Swift protocols
I just found a strange situation in Swift and, typically for that moment when you're learning something, I'm not sure if I've found a bug, a feature or something really clever I just don't understand.
Given the following protocol and default extension
Let's create a base class A that conforms to P, and a subclass B that inherits from A.
A doesn't implement value from the protocol, so any instance of A will use the default implementation, but what about instances of B?
Ok, that's what I would expect. But something funky this way comes when I create a variable of type P and assign an instance of B to it:
The variable p, which is of type P but is an instance of B returns the default implementation of value. The playground itself identifies p as an instance of B, so why don't I see B's implementation of value?
If I change A to implement value (and modify B to override A's implementation) as so:
Then everything works as expected, so what is happening to B when A doesn't implement value?
I would guess that value in B just isn't see as an implementation of P, but if that was the case shouldn't the compiler complain about clashing symbols?
Scratching my head here. If anyone has any ideas, I'd love to hear them
Edit:
Alexandros Salazar (@nomothetis) wrote an article The Ghost of Swift Bugs Future describing something similar to this issue. Alexandros' article focuses more on what happens when you add a new method to a protocol in an extension, but the end result is the same: methods in the extension are being called even if the method is implemented in the class.
Alexandros provides his Rules For Dispatch For Protocol Extensions, which are the following:
- IF the inferred type of a variable is the protocol:
- AND the method is defined in the original protocol
- THEN the runtime type’s implementation is called, irrespective of whether there is a default implementation in the extension.
- AND the method is not defined in the original protocol,
- THEN the default implementation is called.
- AND the method is defined in the original protocol
- ELSE IF the inferred type of the variable is the type
- THEN the type’s implementation is called.
These rules take a bit of digesting, but make some sort of sense. But the issue above, while possibly related, doesn't fit any of the rules. It seems inconsistent with the rules above that the implementation used depends on whether the base class A implements value or not, we're not interested in A, we're interested in B.
I still think this is a bug. Nothing left to do but create a bug report and wait to get shot down in flames!
Edit 2:
It turns out my initial feeling was correct, this is a bug.