Protocol Composition using class, not compatible with Generic parameter requirements?

Hi, I’m a bit stuck, please can anyone point me in the right direction?

We have this init definition:
init<T: StackContainable>(childViewController: T) where T: UIViewController {

So T must conform to StackContainable and be a UIViewController. So far so good.

If I have a class ThisWorksViewController: UIViewController, StackContainable, this can be passed straight in.

However, what I need is to have an array of StackContainable UIViewControllers that can each be passed to the init, so I need to do something like:

let viewControllers: [UIViewController & StackContainable] - i.e. an array of ViewControllers with StackContainable conformance. But for some reason that's eluding me, an element from this array (UIViewController & StackContainable) cannot be passed into that init function, even though it would conform to the generic requirements.

I get this error message:

Cannot invoke initializer for type '...' with an argument list of type '(childViewController: UIViewController & StackContainable)'

I thought protocol composition using & was exactly what was needed here - can anyone shed any light?

Cheers - Ian

Hi Ian,

Protocols or existentials do not conform to themselves. When you pass an array element of type A & B to a function expecting a type that conforms to A & B, you're basically asking for the opposite.

class A {}
protocol P {}

class AP: A, P {}

let array: [A & P] = []

func foo<T: A & P>(_ arg: T) {}

foo(AP()) // OK, AP conforms to P and is a subclass of A

foo(array[0]) // A & P - the type of the array element - does not conform to A & P

Generics are often not necessary when working with existentials unless you're bothering about associated types. Using the type directly lets you pass both instances of a conforming type and instances that are dynamically stored as UIViewController & StackContainable.

init(childViewController: UIViewController & StackContainable) { ... }

The error message really has to be improved though. It's not a big deal to conditionalize the diagnostic based on T == inferred type, but it should be Argument type 'A & B' does not conform to expected type 'A & B' without it.
I'll file a bug anytime soon.

Thanks so much for your fast response - I had to sleep on it but I understand now. Really appreciate it Anthony