Deferring to other implementations for protocol default implementations

I think I know the answer - "no" - but just checking in case I'm overlooking something.

If I extend a protocol to add e.g. a computed property, and it turns out some other protocol does the same (same property name & signature), then that property becomes inaccessible on any type which conforms to both protocols, due to "error: ambiguous use of 'xyz'".

Is there a way to tell the compiler to use my implementation of the property only if the property's not already provided by some other protocol (or of course by the concrete type conforming to the protocol)? A way to specify a "default default" implementation? :slightly_smiling_face:

Only in the very specific case where you know what other protocol it is:

protocol A {}
extension A {
  var xyz: Int { 1 }
}

protocol B {}
extension B {
  var xyz: Int { 2 }
}

extension Int: A, B {}

// Add this, which has a more specific generic signature
extension B where Self: A {
  var xyz: Int { (self as any A).xyz }
}

print(0.xyz)

The "implemented by the concrete type" case is already taken care of by concrete types being considered "more specific" than protocol extensions.

I don't think I actually recommend this, but it is part of the generics system. Which will be documented, maybe, someday.

2 Likes

Ah, that's interesting. It is tempting to do that, but as you allude it's not scalable. If a third protocol were introduced into the mix, even if it does the same thing it seems like the problem would return, since we'd be back to two conflicting definitions of equivalent "priority" so far as the generics system is concerned.

FWIW, my current specific case - which is similar to others I've hit in the past in that involves Stdlib protocols - is for isEmpty, which is defined by Collection but applies to many other situations for things that aren't necessarily Collections. It's defined in terms of count, which I'm also adding and can apparently do so without any ambiguity (according to the compiler), but I can't rely on isEmpty being pre-defined since, again, not every relevant type adopts Collection. It's a pity isEmpty isn't defined to exist whenever count does.

1 Like