Hello, community,
I want to write a function/method with a type parameter, specifically when the input type have constraints like: T: A, in which A is a class type or a non-PAT protocol type, I have 2 options.
I think that the generic one is more performant but has bigger binary size (but both are probably not relevant in a common use case). At the semantic level they're very similar* if you only need to work with the given interface and not on memory-level details.
* should be the difference between "thisT type conforming to P" and "a type conforming to P"
Yeah the main difference is whether the code can use static knowledge about the type or has only access to runtime details. But with "you can use T on the right side of an is operator", don't you mean something like this?
protocol P {}
struct T: P {}
let t: P = T()
if t is T { print("T") }
Because is is a runtime check so it can be done with an existential as well
It's not quite that simple. The optimizer pass for converting existential parameters to generic parameters helps if you call the function with an existential built out of a concrete type, because then we can specialize the generic parameter to the concrete type.
However, none of that should influence the way you write your code; the fact that the optimizer can convert one to the other gives you more freedom, not less.
However, none of that should influence the way you write your code
Thanks, it's very enlightening. After reading your post, I came to realize that the 2 ways of declaring foo have very different semantic meanings.
For example, because a protocol does not naturally conforms to itself, if I have an existential of protocol type P, whose value can only be determined at runtime, the only way to pass it to foo is declaring the function in the 2nd way: func foo(_ type: P.Type, ...).