Conditional conformance for a protocol

Is there a specific name for conditional conformances on a protocol? I mean stuff like this:

extension RawRepresentable: MyProtocol where RawValue: SomeOtherThing {}

I know as of Swift 4.2 this doesn't work but I wish it did. Is this something that's in the works and/or does it need to go through the evolution process and is it even technically possible?

2 Likes

For people who might end up here asking the same question, this is apparently called "Conditional conformances via protocol extensions" as pointed out to me by @ole on Twitter. It's listed in the "Unlikely" section of the Generics Manifesto: https://github.com/apple/swift/blob/master/docs/GenericsManifesto.md#conditional-conformances-via-protocol-extensions

However it seems you can kind of "reverse" the requirements to approach it from a different angle and it does work. For what I was playing with today, it looks like this is just what I needed.

extension MyProtocol where Self: RawRepresentable, Self.RawValue: SomeOtherThing {}
3 Likes

Yeah, the first one looks simple, but it ends up being a relatively complicated feature, or at least one where lots of questions need to be answered[1], while the second is simpler. In a human language, the two mean:

  1. anything that conforms to RawRepresentable also conforms MyProtocol (and can do the things in the extension), including all the dynamic features of protocols and their requirements
  2. anything that conforms to both RawRepresentable and MyProtocol can do the things in the extension (but this is only if the thing being operated on is statically known to conform to both)

That is, the first is actively adding a new conformance, even if it wasn't explicitly stated, while the second is just adding extra functionality for types that (explicitly) conform to both protocols.

[1]: For instance, do we allow someone to write the second extension in extension X: RawRepresentable {} extension X: MyProtocol {}, since X gets a conformance to MyProtocol through the first one? What if there's three protocols P, Q and R with extension Q: P {} extension R: P {} and some type conforms to both Q and R? And, all of this exacerbates the existing difficulties with overlapping retroactive conformances in "downstream" modules.

I have had a few thoughts on this topic, but I have never managed to solidify them enough to consider posting them directly.
The idea I have had is that if and only if P is from the current module and Q was not (or was it vice versa?), then the following would be permitted:

extension Q: P {
  // must contain implementations for all requirements of P,
  // (in terms of the requirements of Q) not also required by Q.
  // These implementations will be the ones called when a conformer to Q is used as a P
}

In addition any conformance of a type to P when it already conforms to Q would be either as if Q inherited from P or an error, IDK which.
The requirement that one of the protocols is from the current module would be to prevent a module from seeing any 2 of P, Q and the conformance without also seeing the third.