Search code examples
swiftswift-protocolsassociated-types

protocol with same associated type name


If I have two protocols whose associated type happens to be the same, such as

protocol Read {
    associatedtype Element
    func read() -> Element
}
protocol Write {
    associatedtype Element
    func write(a: Element)
}

Then I would like to have a class to read integer from and write string to:

class ReadWrite: Read, Write {
    func read() -> Int {
        return 5
    }
    func write(a: String) {
        print("writing \(a)")
    }
}

but the compiler complains and suggests changing String to Int. Ideally the type should be inferred, or at least compiles if I explicitly declare

associatedtype Read.Element = Int
associatedtype Write.Element = String

within ReadWrite. Any work around?

update

Workaround inspired by this question is to create two auxiliary protocols

protocol ReadInt: Read {
    associatedtype Element = Int
}
protocol WriteString: Write {
    associatedtype Element = String
}

and have the class inherit from these two instead:

class ReadWrite: ReadInt, WriteString {
    func read() -> Int {
        return 5
    }
    func write(a: String) {
        print("writing \(a)")
    }
}

This seems to compile, but I am afraid of any gotcha following this way.

update again

I found the issue in Swift's issue tracker. Anyone require this missing feature (like me) should vote for it. As a comparison, this pattern is possible in Rust, which also supports associated types (although this is not an idiomatic usage).


Solution

  • Another workaround is to create a third, combined protocol:

    protocol ReadWrite {
        associatedtype R
        associatedtype W
        func read() -> R
        func write(a: W)
    }
    

    It's not pretty, since it forces you to redeclare the protocol members, but it does keep it generic (you're not limited to String and Int).