A simplified version of my code which shows the problem:
protocol Transformer {
typealias Input
typealias Output
func transform(s: Input) -> Output
}
protocol InputType {}
protocol OutputType {}
extension Int: OutputType {}
extension String: InputType {}
struct StringToInt: Transformer {
typealias Input = String
typealias Output = Int
func transform(s: Input) -> Output {
return s.characters.count
}
}
typealias Transform = InputType -> OutputType
func convert<T: Transformer where T.Input == InputType, T.Output == OutputType>
(transformer: T) -> Transform {
return transformer.transform
}
convert(StringToInt()) // error: Cannot invoke 'convert' with an argument list of type '(StringToInt)'
I'm guessing that the error occurs because the compiler cannot reach into StringToInt
and verify that Input
and Output
indeed conform to InputType
and OutputType
respectively.
For me, the best way to solve this would be to constrain the associated types directly in the protocol. It would be more expressive and the compiler would have more information. But simply doing typealias Input: InputType
doesn't work.
Is there any way to constrain an associated type?
You can create extension for Transformer
protocol
extension Transformer where Input: InputType, Output: OutputType {
func convert() -> Input -> Output {
return transform
}
}
Now you can call convert
method on StringToInt
instance.
StringToInt().convert()
But for other type that doesn't have Input
and Output
adopting InputType
and OutputType
it won't compile
struct DoubleToFloat: Transformer {
func transform(s: Double) -> Float {
return Float(s)
}
}
DoubleToFloat().convert() // compiler error