iandundas
(Ian Dundas)
1
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.
iandundas
(Ian Dundas)
4
Thanks so much for your fast response - I had to sleep on it but I understand now. Really appreciate it Anthony