Conditional conformances, what now?

I really appreciate that this feature finally made it into the wild. However I'm someone who wanted it so many times but now used to the fact that it didn't exist and designed my codebase differently. I have a huge project I'm working on currently but I really don't know if this feature fits anywhere. Sure it also does not mean that I'm forced to use it at all, but still I feel a little lost.

That said, I would like to gather a few ideas on how you guys are adopting it into your codebase.

Here's something I just stumbled upon the other day. Conditional conformances can reduce as? casting and remove optionals from your code.

I have a framework which provides model objects. Some of these model objects have custom styling information, because they relate to co-marketing deals with 3rd-parties. I wrap the model objects in some information about how they were calculated (is it fresh from the server or did some parts of it come from the cache?).

Now I want to say: if the wrapped-type conforms to the Cobranded protocol, my wrapper should also conform to Cobranded and forward the wrapped value. Previously, my wrapper would always have to conform, and the result would have to be Optional to account for the possible failure:

protocol Cobranded {
  var brandingID: Branding.ID? { get }
}

extension Wrapper: Cobranded {
  var brandingID: Branding.ID? { return (result as? Cobranded)?.brandingID }
}

// or something like this, if there are lots of things to forward...
extension Wrapper {
  var cobranded: Cobranded? { return (result as? Cobranded) }
}

This doesn't work with non-as?-castable protocols, such as those with associated types (it also won't work if Wrapper.result only conditionally conforms to Cobranded, since that's not implemented yet). With conditional conformances, we can remove the optional and make the checks happen at compile-time instead of run-time:

protocol Cobranded {
  var brandingID: Branding.ID { get }
}

extension Wrapper: Cobranded where Result: Cobranded {
  var brandingID: Branding.ID { return result.brandingID }
}

Now the only place I can use my Wrapper as a Cobranded are when the wrapped result really has branding information. Thanks, CC!

In general, I think generic wrappers really benefit the most.

4 Likes