Reputation: 585
I have the following setup:
protocol Resource : Codable {}
class A<T> {}
extension A where T : Codable {
func doThingWithCodable() {}
}
let a = A<Resource>()
a.doThingWithCodable()
//Error: Protocol type 'Resource' cannot conform to Codable because
//only concrete types can conform to protocols.
I understand the error message, and I've read numerous Q&A's on generics, protocols and conditional conformance. I have a number of classes that conform to the Resource
protocol, so it'd be really convenient if there was a way to let A<Resource>
know that it will always be working with concrete types that conform to Codable
, so I could still have one instance of A<Resource>
, and that instance could have access to its conditional Codable
methods. I did think about just making an instance like A<Codable>
, but I need some of the properties that are inside the Resource
protocol too.
Is there a swifty way to resolve this besides creating a new instance of A
for each concrete type that conforms to Resource
?
Upvotes: 2
Views: 138
Reputation: 2100
Just think about this:
let a = A<Resource>()
This statement is trying to create an instance of class A
and assigning it to a
. The compiler doesn't know what this resource exactly is and how much memory it should allocate and what optimization it should run; because here Resource
can be anything.
To resolve that, you need to provide little more information i.e. which you are already aware of.
struct CoffeeResouce: Resource {
let isWarm: Bool
}
Now when you write this:
let a: A<CoffeeResource> = A()
The compiler is well about the type and it's memory requirements. This is one way of resolving.
Or permanently tell the class that T
conform to the protocol by declaring the class.
class A<T: Resource> {}
Upvotes: 0
Reputation: 534893
The question as posed, "How can I get conditional protocol conformance with a protocol's parent?" is meaningless, because a protocol always conforms with its parent; there is no "conditional" about it.
As for your actual code, the problem is the phrase A<Resource>
. Saying A<Resource>
is not a correct resolution of A's T. You need to resolve T as a class, struct, or enum — not as a protocol.
For example, if you have a class B that conforms to Resource, you can declare
let a = A<B>()
and all is well.
if there was a way to let
A<Resource>
know that it will always be working with concrete types that conform toCodable
Well, as I said, your code compiles fine as soon as A is working with a concrete type that does conform to Codable
. So if that's what A will always be working with, there's nothing more to do. You could of course tell A that its T will always conform to Resource (which by definition will always conform to Codable):
class A<T:Resource> {}
Upvotes: 2