Search code examples
swiftswift-protocolsassociated-types

Constrain an associated type


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?


Solution

  • 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