Generics and type variable does not compile

Hi fellow Swift-developers,

I ran into problem that puzzles me. I wanted to do something like:

protocol A : Codable {}
class B : A {
var prop = "some stuff"
var json: Data { get { return try! JSONEncoder().encode(self) } }
}

let type : A.Type = B.self
JSONDecoder().decode(type, B().json)

But it does not compile. Error is:
Error:(19, 42) cannot invoke 'decode' with an argument list of type '(Codable.Type, from: Data)'

However, replacing the variable type, with B.self in the call to decode works fine. Like this:

JSONDecoder().decode(B.self, B().json)

I can't understand why the compiler won't accept both.
Thanks in advance for any hints or explanations.

/PO

When you call decode with type, the inferred generic parameter is A, which doesn't conform to Decodable because protocols do not conform to other protocols.

Thanks a lot.

You may also want to wrap such code with a generic context to avoid passing protocols to generic functions with conformance requirements.
For example,

protocol A : Codable {
    init()
    var json: Data { get }
    func decode()
}
extension A {
    var json: Data {
        get { return try! JSONEncoder().encode(self) }
    }
    
    func decode() {
        try! JSONDecoder().decode(Self.self, from: Self().json)
    }
}

class B : A {
    required init() {}
    var prop = "some stuff"
}
1 Like

@anthonylatsis I am not sure I get the wrapping, since it seems to me that it takes away the benefit of the automatic synthesized "stuff" that comes with the Codable protocol.

What problem does wrapping solves in this case?

As long as the relevant type can conform to Codable, the conformance will be synthesized.
Assuming protocol A is supposed to be used with a family of codable entities, I generalized decoding over anything that conforms to A using a convenience function. This way you don't have to worry about type safety or calling through to JSONEncoder and passing the already derived arguments. On the other hand, the helper function could of course be declared on B for an isolated case. For instance, when another class conforming to A uses a different coding strategy.

OK, thanks @anthonylatsis for taking your time to explain it to me. Now I get the wrapping.

Cheers!

1 Like