MrJre
MrJre

Reputation: 7161

Generic Default argument value of type cannot be converted

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

Answers (1)

Palle
Palle

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

Related Questions