Need Help Understanding Protocols and Generics

override is implied by having the same requirement stated in a more-refined protocol as in a protocol it inherits from. It is allowed to be stated explicitly primarily to suppress the warning produced by -warn-implicit-overrides.

What you surmise is correct. When a protocol requirement "overrides" one from an inherited protocol, this requirement always gets the same witness as that of the inherited protocol. At the implementation level, there is no new entry for an override requirement in the witness table.

This is correct.

@_nonoverride says that the restated requirement does not have to have the same witness in a more-refined protocol as in the protocol it inherits that originally stated the requirement. In the implementation, this means that a @_nonoverride requirement introduces a new entry in the witness table. If you look at where @_nonoverride is used in the Standard Library, they are for cases where the semantics or complexity of operations (like distance(from:to:)) change in the protocol inheritance hierarchy: distance(from:to:) on a Collection is forward-only, on a BidirectionalCollection can go backwards, and on a RandomAccessCollection is

@_nonoverride is very, very important when dealing with conditional conformances, because it gives you more-capable witnesses in your conformances to protocols like BidirectionalCollection. Without it, for example, a wrapper around a Collection that had a conditional conformance to BidirectionalCollection would not be able to provide a more-specialized implementation of the wrapper semantics for bidirectional collections.

Note how this is the same problem we've been discussing, where we really want to be able to pick a more-specialized witness when we have a more capable type. The override / @_nonoverride dance was an implementation band-aid to get conditional conformances in the standard library to provide (mostly) the right behavior, using an ABI we could live with.

Doug

8 Likes