0

I will try to demonstrate what I mean with an example.

Say I have this protocol:

protocol P {}

And these types that are conforming to it:

struct S1 : P {}
struct S2 : P {}

And finally, this generic method that accepts one parameter which is any type conforming to protocol P:

func f<T>(type: T.Type) where T : P {
    // ...
}

Now there is no problem in passing S1.self or S2.self to f.

f(type: S1.self) // No problem!
f(type: S2.self) // No problem!

But if I want to add S1.self and S2.self to an array

let types: [P.Type] = [S1.self, S2.self]

I won't be able to pass to f a type from this array.

f(type: types[0]) // ERROR: Cannot invoke 'f' with an argument list of type '(type: P.Type)'

I don't understand what I'm doing wrong. Any help would be greatly appreciated.

3li
  • 598
  • 3
  • 13
  • This is related to [Protocol doesn't conform to itself?](https://stackoverflow.com/q/33112559/1187415) and unrelated to arrays. `let t: P.Type = S1.self ; f(type: t)` would not compiler either. – Martin R Jul 08 '19 at 12:46

2 Answers2

1

Swift needs to be able to determine the type of the generic function at compile time. A call to a generic function gets turned into a explicit call handling only a single type. You are trying to turn that into a runtime decision which will not work.

If you want to call f(type:) with a value from your array, you will have to establish its type before making the generic call.

For example, this can be done with a switch:

switch types[0] {
case let type as S1.Type:
    f(type: type)
case let type as S2.Type:
    f(type: type)
default:
    break
}

or with an if case let:

if case let type as S1.Type = types[0] {
    f(type: type)
}
vacawama
  • 150,663
  • 30
  • 266
  • 294
1

That is not possible for function arguments. Because using generic T: P is like: I don't know what type it has but it must conform to P. The compiler infer the type when you pass an argument to the function.

So the problem is with the array of generics you used. It can fill array but when you call some index of the array, It will return An Unknown Type conformed to P. So it can not infer the generic Type T from it

So you should tell it your self what type is it:

f(type: types[0] as! S1.Type)

And if you don't know what type is it, you can check it before calling the function:

switch types[0] {
case is S1.Type: f(type: types[0] as! S1.Type)
case is S2.Type: f(type: types[0] as! S2.Type)
default: break
}