cweber105
cweber105

Reputation: 585

How can I get conditional protocol conformance with a protocol's parent?

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

Answers (2)

Rahul
Rahul

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

matt
matt

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 to Codable

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

Related Questions