Search code examples
swiftgenericsprotocolsassociated-types

How to constrain generic function associated types


I'm trying to take two protocols that both have the same associated type and return the same type, but not having luck.

protocol MyProtocol {
    associatedtype AssociatedType
}

func myFunc<T: MyProtocol, R: MyProtocol>(arg: T) -> R
    where T.AssociatedType == R.AssociatedType {
        return arg //Error-> Cannot convert return expression of type 'T' to return type 'R'
}

Is something like this possible in Swift?


Solution

  • Two types (call them T and R) are not the necessarily the equivalent just because they conform to the same protocol and use the same associated type.

    By that reasoning, Array<Int> is the same as Set<Int>, and should be freely interchangeable, because they both conform to Collection where the Element is Int.

    Here's another counter example:

    protocol MyProtocol {
        associatedtype AssociatedType
    
        init()
    }
    
    protocol MySubProtocol1: MyProtocol where AssociatedType == Int {}
    protocol MySubProtocol2: MyProtocol where AssociatedType == Int {}
    
    struct S1: MySubProtocol1 {}
    struct S2: MySubProtocol2 {}
    
    func myFunc<T: MyProtocol, R: MyProtocol>(arg: T) -> R
        where T.AssociatedType == R.AssociatedType {
            return arg as! R // Let's see what would happen. Don't do this!
    }
    
    func produce<T: MySubProtocol1>(type: T.Type) -> T {
        return T()
    }
    
    func consume<T: MySubProtocol2>(arg: T, ofType: T.Type) {
        print(arg)
    }
    
    consume(arg: myFunc(arg: produce(type: S1.self)), ofType: S2.self)
    

    Terminated due to signal: ABORT TRAP (6)

    Could not cast value of type 'main.S1' (0x100e44210) to 'main.S2' (0x100e44228).