I have a requirement where I have multiple struct
conforming to protocol P, which I later make a collection of and execute methods like compute()
via a Computer
struct which helps in creating an instance of each conforming type
Why would the following code not run and what changes are required to make it run:
import Foundation
protocol P {
static func instance() -> Self
}
struct A: P {
static func instance() -> A {
A()
}
}
struct B: P {
static func instance() -> B {
B()
}
}
struct Computer<T: P> {
static func compute() -> T {
T.instance()
}
}
let someArray: [P.Type] = [
A.self,
B.self
]
for value in someArray {
Computer<value>.compute() // ERROR: Cannot find type 'value' in scope
}
2
Answers
You don’t need the generic constraint if you pass the type as a variable to
compute
like this:Alternatively, if the resulting type of
compute
should not beP
explicitly, you could put the generic constraint into the method:And then call
compute
like this:This assumes that
P
has the methoddoSomething
. If you want to access a method that is specific toA
, you will always need to type cast. In the endinstance
will always be aP
to the compiler, because it has to assume that the same code will be executed for any values withinsomeArray
, which isP.Type
. No matter whethercompute
returnsP
or explicitlyT
,instance
will still be inferred to beP
if you place it in a loop like this.If you did not require the generic
Computer
struct, then you could directly extend P(which is functionally the same as @JanMensch’s answer)but if you needed it, I don’t think this would be possible. You’re trying to create a new type at runtime (
Computer<A.Type>
andComputer<B.Type>
). You cannot do that. Swift Generics only help with code duplication, AFAIK.EDIT:
I have another roundabout solution where the
Compute<>
is transient in a extension on P. However, I’m not sure if this would fit your use case without additional information, though.