How to call a generic function with a parameter of a related type in Swift 3
Here's my sample code:
protocol P {
}
protocol B {
associatedtype ID: P
}
class MyClass: B {
enum ID: P {
case one
case two
}
}
func process<T: B>(_ value: T.ID) {
// do something
}
process(MyClass.ID.one) // Compile Error: cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'
As you can see, I define a generic function with a parameter whose type is associated type of general type T . How can I call this function? I want to use MyClass.ID.one as an argument, but the compiler gives the following warning:
cannot convert value of type 'MyClass.ID' to expected argument type '_.ID'
source to share
It looks like Swift has an issue of deducting T
from a call starting with MyClass.ID
, is T.ID
, and for is MyClass
used T
.
If you change your function to take an additional type parameter T
, the code compiles and works fine:
func process<T: B>(_ value: T.ID, _ workaround : T) {
// do something
}
let workaround = MyClass()
process(MyClass.ID.one, workaround)
Swift designers can approach this inference problem in two ways:
- Correct the inference engine to resolve this use case, or
- Simplify the inference engine for definition
T
by applying stricter rules for function signatures.
It looks like they solved the second approach with Swift 4, because the original function won't compile, throwing the following error:
generic parameter is
'T'
not used in function signature
Better work to pass a type instead of an instance using a Java style approach:
func process<T: B>(_ value: T.ID, _ workaround: T.Type) {
// do something
}
...
process(MyClass.ID.one, MyClass.self)
source to share
dasblinkenlight gives a good answer to the question of why your current implementation is not working. If the decisive resolution is simply to find another way to implement this feature, I would go for a less hacky solution:
extension B {
static func process(_ value: Self.ID) {
//do stuff
}
}
MyClass.process(.one)
This takes advantage of the more flexible type inference achieved with a protocol extension Self
.
source to share