Why does f2(p: f1()) compile ok but f3(p: f1()) throws an error ?
Code
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())
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)