On specializing an extension method based on a second protocol conformance (attn: RangeSet)

I'm trying out a Swift package on Xcode 12 beta 4 on a Big Sur public beta system (on an external drive). I have the SE-0270 package added. The code in that package has this method:

extension RangeReplaceableCollection {
  /// Removes the elements at the given indices.
  public mutating func removeSubranges(_ subranges: RangeSet<Index>) { /*...*/ }
}

and another method that specializes the above routine when the collection also supports per-element mutability:

extension MutableCollection where Self: RangeReplaceableCollection {
  /// Removes the elements at the given indices.
  public mutating func removeSubranges(_ subranges: RangeSet<Index>) { /*...*/ }
}

You can't extend on "A & B," where A and B are any two given distinct protocols. But you can extend on exactly one then specify the co-protocol(s) with Self-based conditional conformance. Mechanically, usage of the method doesn't care which protocol is the primary. However, it does matter spiritually.

The removeSubranges(_: ) method changes the length of the receiver, so it belongs to RangeReplaceableCollection. MutableCollection is for per-element mutations that don't change the receiver's length. Actually, it's more than spiritual: the primary protocol is where the method's documentation goes, and this method definitely belongs to RRC over MC on that aspect!

The moral of this story is: if you extend a protocol with a method, then re-extended with an optimized implementation when the conforming type matches other protocols, make sure to keep the primary type for the extension the same, and keep the optimized protocol(s) as Self conformances. This keeps the documentation in the right place.

Officially noted this for RangeSet as SR-13378, "A range-set method overload needs to be moved."

Terms of Service

Privacy Policy

Cookie Policy