[swift-evolution] PITCH: New :== operator for generic constraints

Slava Pestov spestov at apple.com
Tue Aug 16 20:13:19 CDT 2016

-1 — this adds a new syntax with little gain, and potentially a lot of additional complexity.

> On Aug 16, 2016, at 2:49 PM, Charles Srstka via swift-evolution <swift-evolution at swift.org> wrote:
> Unfortunately, when this has come up on the list in the past, it has been mentioned that there are some cases where an existential of a protocol does not conform to the protocol itself, so it is impossible to make : always match items that are typed to the protocol.

Indeed, the best solution IMHO would be to implement self-conforming protocols, so that what you’re describing can be expressed without any additional syntax.

The condition for a protocol to be able to conform to itself is the following:

- it must not have any associated type requirements, or contravariant Self in requirement signatures; eg, this rules out the following:

  protocol P { func foo(s: Self) }

- it must not have any static method or initializer requirements

With these conditions met, it would be possible to allow a generic parameter ’T : P’ to bind to a concrete type ’P’.

Note that the type checker work required for this is not very difficult. Indeed, we already allow @objc protocols that don’t have static requirements to self-conform. The real issue is the runtime representation gets tricky, if you want to allow a generic parameter to contain both a concrete type conforming to P, and an existential of P. Basically a generic parameter is passed as three values behind the scenes, the actual value, type metadata for the concrete type, and a witness table for the conformance. To allow the parameter to be bound to an existential type we would need to pass in a special witness table that unpacks the existential and calls the witness table contained in the existential.

It’s even worse if the protocol that self-conforms is a class-bound protocol. A generic parameter conforming to a class-bound protocol is passed as a reference counted pointer and witness table. Unfortunately, a class-bound existential is *not* a reference counted pointer — it has the witness table ‘inside’ the value.

Probably my explanation isn’t great, but really what’s bothering you here isn’t a language limitation, it’s an implementation limitation — once we figure out how to represent protocol existentials efficiently in a way allowing them to self-conform, we should be able to address these use-cases without new syntax.



More information about the swift-evolution mailing list