Hello,
Does anyone know the rationale behind Swift favoring static dispatch in this context (attached screenshot), instead of considering witnesses within the class hierarchy?
Thanks in advance for your answer.
Hello,
Does anyone know the rationale behind Swift favoring static dispatch in this context (attached screenshot), instead of considering witnesses within the class hierarchy?
Thanks in advance for your answer.
This is one of the oldest bugs in the language: [SR-103] Protocol Extension: function's implementation cannot be overridden by a subclass
Good to see it is on the community's radar.
I'm puzzled as to why this bug has not yet been addressed since 2015.
Itâs not really a bug but rather a consequence of how protocol conformances work, but we should probably emit a warning in this situation.
If a superclass A
conforms to P
but uses a default implementation for one of the requirements (echo
), then there is no âslotâ in the class vtable for a A
corresponding to the echo
requirement. As a subclass, B
doesnât get its own unique conformance to P
ârather it has to reuse A
âs conformance, including the âuse default echo
implementationâ part of that conformance. And since A
has no actual echo
method, B
cannot override the default implementation that A
used. So even if there is an echo
method on B
, itâs not registered as being part of the conformance.
It is not (notionally) statically dispatched. There is only one witness to the protocol requirement and it is the extension method, for the reasons outlined above by @Jumhyn.
The emitted warning should say that the concrete method echo
shadows but does not override the default implementation.
I think you mean there's no slot in the class vtable, not in the protocol conformance. A protocol conformance always records an implementation for each protocol requirement. If the implementation is declared in a protocol extension, the corresponding entry points at the protocol extension method. If the implementation is declared inside a class, the entry points at a thunk which loads the entry from the class's vtable and calls it. Method overrides in a subclass are implemented by the subclass replacing the vtable entry with its own implementation.
This behavior falls out from the table-driven dispatch used for protocol conformances and class methods. To allow a subclass to override a default implementation would require a more general dispatch mechanism, like objc_msgSend()
or similar.
Ah, yeah, you're rightâI misremembered the details here. Edited to clarify, thank you!
Technically, it would only require that when the conformance is declared via an extension to the class.
If the conformance is declared at the class definition site, then it would theoretically be possible for the compiler to include these methods within the class vtable âas ifâ they had been written out manually.
Yes, you're absolutely right, but the extension thing means it's still a leaky abstraction and the limitations of table dispatch cannot be completely papered over.
I wonder if there might someday be a way to let people make it explicit. Like â@allowDefaultOverrides(Protocol)
â within the main body of a class or something.
If we introduced a way to refer to the default implementation directly rather than only via witness (e.g. via some fully-qualified name syntax), classes could make this explicit by providing the echo()
function and having the implementation be, say:
self.P::echo()