Reputation: 99
I have a Session
protocol with an Output
associated type:
public protocol SessionAPI {
associatedtype Output: Equatable
var output: Output { get }
}
And a concrete implementation of the protocol that returns a String
:
public final class StringSession: SessionAPI {
public typealias Output = String
public let output: String
}
Let's assume that the implementation of StringSession
is very complex and touches many modules, and I don't want to add dependencies to those modules in classes that use the SessionAPI. So I have another protocol that vends StringSessions using a generic factory method:
public protocol SessionFactoryAPI {
func createStringFactory<T: SessionAPI>() -> T where T.Output == String
}
All of this compiles fine. However, when I try to implement the factory API, I get a compilation error:
public final class SessionFactory: SessionFactoryAPI { public func createStringFactory<T: SessionAPI>() -> T where T.Output == String { // Error: Cannot convert value of type 'StringSession' to expected argument type 'T' return StringSession() } }
Does anyone have any suggestions on how to get this to work?
Upvotes: 1
Views: 58
Reputation: 2671
Error: Cannot convert value of type 'StringSession' to expected argument type 'T' return
Means that the compiler doesn't know that T
should be SessionAPI
.
In SessionFactoryAPI
:
public protocol SessionFactoryAPI {
func createStringFactory<T: SessionAPI>() -> T where T.Output == String
}
you are only specifying what T.Output
should be (ie. String
)
If you really need the constraint Output == String
, you can try declaring a StringSessionAPI
protocol:
public protocol StringSessionAPI: SessionAPI where Output == String { }
public final class StringSession: StringSessionAPI {
public typealias Output = String
public let output: String
public init(output: String) {
self.output = output
}
}
and return any StringSessionAPI
public protocol SessionFactoryAPI {
func createStringFactory() -> any StringSessionAPI
}
struct MyFactory: SessionFactoryAPI {
func createStringFactory() -> any StringSessionAPI {
StringSession(output: "output")
}
}
let factory = MyFactory()
let stringSession: any StringSessionAPI = factory.createStringFactory()
print(stringSession.output) // prints "output"
Or you can try using by using an associated type, instead of a generic function:
public protocol SessionFactoryAPI {
associatedtype T: SessionAPI where T.Output == String
func createStringFactory() -> T
}
struct MyFactory: SessionFactoryAPI {
func createStringFactory() -> StringSession {
.init(output: "output")
}
}
let factory = MyFactory()
let stringSession: StringSession = factory.createStringFactory()
print(stringSession.output) // prints "output"
Upvotes: 0