Generics + Protocol


I have a doubt regarding Generics and Protocols.


  • Why does f2(p: f1()) compile ok but f3(p: f1()) throws an error ?


protocol P {}

struct S1 : P {}

func f1() -> P {
    return S1()

func f2(p: P) {}

f2(p: f1())

func f3<T>(p: T) where T : P {}

//Compilation Error: Protocol type 'P' cannot conform to 'P' 
//because only concrete types can conform to protocols
//f3(p: f1())


There is a small difference between the two:

func f3<T>(p: T) where T : P {}

This one says "give me a concrete type T which conforms to P"

func f2(p: P) {}

This one says "give me the P existential"

Since protocols in Swift do not conform to themselves*, you cannot pass P to a function which takes T: P.

*except Error which is a special case.

1 Like

Thanks a lot @suyashsrijan,

Pardon my ignorance, I am a little confused about the following:


  • What does existential mean ? Are you referring to P.Type.self ?
  • Protocols in Swift do not conform to themselves, could you explain.

An existential is essentially a "box" that can hold a value of any concrete type conforming to a protocol P, or at least that's how I think of it at a high level. Here's a quote from Improving the UI of generics that offers a bit more information:


Thanks a ton @suyashsrijan, I understand better now.

It also explains why f3 can accept an Opaque type. which has type identity as it points to a specific type (underlying type is not visible to the caller yet specific)