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?
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.
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).
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).