I have a Client
protocol that looks like this:
protocol Client {
func get<T>(_ url: String) -> Promise<T>
}
Now, the problems start when I try to implement it. I want to have 2 types of clients: AlamofireClient and MockClient (maybe in the future more, like ErrorClient etc. but let's start simple)
so I need something like:
final class AlamofireClient: Client {
func get<T: Decodable>(_ url: String) -> Promise<T> {
(...)
}
}
and:
final class MockClient: Client {
func get<T: Mockable>(_ url: String) -> Promise<T> {
return Promise { seal in
seal.fulfill(T.mock())
}
}
}
here the simple Mockable interface that every entity in the app will implement:
public protocol Mockable {
static func mock() -> Self
}
But I always get the error:
Type 'MockClient' does not conform to protocol 'Client'
Type 'AlamofireClient' does not conform to protocol 'Client'
That's because is not the same as <T: Decodable> and <T: Mockable>
Is there an elegant way to solve this issue? I'm not able to find an elegant solution for this problem. Maybe the whole idea is just bad? I also tried solving the problem with PATs but also no luck there.
The way you have it written, by conforming to the protocol Client, you have to implement a function get
, with a generic, unconstrained argument T
. In the example implementations provided, you added a type constraint to the generic parameter T
, which does not match the function in the protocol.
There's more than one way you can approach a solution to this problem. Keeping in mind that you said all entities will conform to Mockable
, the solution that requires the least change to the code you provided is to use protocol composition to enforce that all parameters T
conform to both Decodable
and Mockable
.
protocol Client {
func get<T: Decodable & Mockable>(_ url: String) -> Promise<T>
}
In your clients, you would implement that function exactly as written.
Now, in your MockClient
, you can call T.mock()
, and in your real implementations, you can treat T
as Decodable
as required. Of course, this now requires that even your mock arguments conform to Decodable
, but I would assume your mock arguments will be fairly lightweight and thus this wouldn't be a problem.