Reputation: 49590
I am trying to create a Fetchable
protocol that contains the location of where to get the objects from as part of its type, and instead of writing the fetch
function with an explicit type parameter, like this:
func fetch<Model: Fetchable>(_ type: Model.Type, path: Model.Path) -> AnyPublisher<[Model], Error> {
print(path.value)
// ...
}
I would like Model
to be inferred from the Model.Path
parameter:
func fetch<Model: Fetchable>(path: Model.Path) -> AnyPublisher<[Model], Error> {
print(path.value)
// ...
}
This is inspired by @RobNapier's approach here. It's not exactly the same, and so I might be missing salient details to make it work.
Here's what I have:
protocol Locatable {
associatedtype Model
var value: String { get }
}
protocol Fetchable: Codable {
associatedtype Path: Locatable where Path.Model == Self
}
struct Message {
let content: String
}
extension Message: Fetchable, Codable {
enum Path: Locatable {
typealias Model = Message
case forUser(_ userId: String)
var value: String {
switch self {
case .forUser(let userId): return "/user/\(userId)/messages"
}
}
}
}
When I call fetch
, I get an error "Generic parameter 'Model' could not be inferred"
let pub = fetch(path: Message.Path.forUser("123"))
But this works with a fetch
that accepts the type parameter explicitly (even infers its own Message.Path type):
let pub = fetch(Message.self, .forUser("123"))
Any idea how (if possible) to solve this?
Upvotes: 1
Views: 130
Reputation: 257869
It is not enough information to infer, but if we write
let pub: AnyPublisher<[Message], Error> = fetch(path: Message.Path.forUser("123"))
everything goes well.
Update: nested type is just a type it is not dividable, so to help swift to infer parent we need to reverse declaration, like below (tested with Xcode 12.1):
func fetch<Path: Locatable>(path: Path) ->
AnyPublisher<[Path.Model], Error> where Path.Model: Fetchable {
and now your desired expression becomes possible
let pub = fetch(path: Message.Path.forUser("123"))
Upvotes: 2