Reputation: 7161
I have a simple ParserType
, a PAT looking like this:
public protocol ParserType {
associatedtype ModelType
func parse(_ data: Any?) throws -> ModelType
}
I have a WebService
:
public class WebService<ModelType, Parser: ParserType> {
public typealias ModelType = Parser.ModelType
private let parser: Parser
...
public init(transport: ServiceTransport, endpoint: String, parser: Parser) {
self.transport = transport
self.endpoint = endpoint
self.parser = parser
}
func fetch(...) -> ModelType {
...
let result: ModelType = try! self.parser.parse(data)
return result
}
}
And a simple parser:
public class SimpleJSONParser<T: Codable>: ParserType {
public typealias ModelType = T
private let jsonDecoder: JSONDecoder
public init(jsonDecoder: JSONDecoder = JSONDecoder()) {
self.jsonDecoder = jsonDecoder
}
open func parse(_ data: Any?) throws -> T {
let response = try jsonDecoder.decode(T.self, from: data as! Data)
return response
}
}
This works as expected.
However when I want to add a WebService subclass with a default parser, i.e.
class SimpleWebService<T: Codable, Parser: ParserType> : WebService<T, Parser> {
override init(transport: ServiceTransport, endpoint: String, parser: Parser = SimpleJSONParser<T>()) {
super.init(transport: transport, endpoint: endpoint, parser: parser)
}
}
I get the following error:
Default argument value of type 'SimpleJSONParser<T>' cannot be converted to type 'Parser'
. I would think SimpleJSONParser
adheres to ParserType
, but the compiler seems to think otherwise. Why is that?
Upvotes: 1
Views: 510
Reputation: 12109
By leaving the Parser generic, a SimpleWebServer
may be instantiated with a parser type other than SimpleJSONParser
(e.g. let service = SimpleWebService<..., SimpleXMLParser>(...)
so you have a conflict between SimpleJSONParser
and the generic type Parser
which would be specialized to SimpleXMLParser
.
So you would have to use a generic same-type constraint in an extension to add your initializer with a default value:
extension SimpleWebService where Parser == SimpleJSONParser<T> {
convenience init(transport: ServiceTransport, endpoint: String, parser: Parser = SimpleJSONParser<T>()) {
super.init(transport: transport, endpoint: endpoint, parser: parser)
}
}
Note however that this code would not compile as it is currently not allowed to override a method in an extension.
Upvotes: 1