Yeah, this is a really sticky area of the language, one where my reasoning often fails. The root of it all, I think, is that Swift extensions can express two very different things:
- properties of values themselves, but also
- properties values acquire from local assumptions in the context where they’re used.
It’s confusing that extension
means both of these things.
In Dave’s example in that second link, this dynamically dispatched code:
extension P {
static var isEquatable: Bool { false }
}
…is something that the value itself knows — “I am not equatable” — whereas this statically dispatched code (which if I understand correctly is a shadow, not an override):
extension P where Self : Equatable {
static var isEquatable: Bool { true }
}
…is tied to something the calling context knows — “if you think I implement the Equatable
protocol, then I guess I’m equatable!” Dave’s example goes haywire because the local assumptions (the static types) that could expose this isEquatable
implementation don’t travel around with the value itself.
This all makes sense in terms of the language specification and implementation, but it’s hard to reason intuitively about. It feels like the Liskov Substitution Principle’s bohemian cousin.
Back to the problem at hand: I don’t think you can get things to make sense again here without doing some kind of runtime test based on metadata that lives with the value itself. Whether that’s an expensive type metadata search with is
or the vtable lookup I sketched, it has to be dynamic.