Fulfilling an array of "existenstials" requirement with an array of "concrete types"

Hi,
Here I'm trying to get Bar to conform to both BarProtocol and Codable:

// ModuleA
public protocol FooProtocol {
    var fooValue: Int { get }
}
public protocol BarProtocol {
    var foos: [FooProtocol] { get }
}
public func load(bar: BarProtocol) {
    for foo in bar.foos { /* ... */ }
}

// ModuleB
import ModuleA
struct Foo: Codable, FooProtocol {
    var fooValue: Int
}
struct Bar: Codable, BarProtocol { // ❌ Type 'Bar' does not conform to protocol 'BarProtocol'
    var foos: [Foo]
}
func test() throws {
    let data = """
    {"foos" : [ {"fooValue" : 42} ] }
    """.data(using: .utf8)!
    let bar = try JSONDecoder().decode(Bar.self, from: data)
    ModuleA.load(bar: bar)
}

Unfortunately the var foos: [FooProtocol] requirement cannot be fulfilled with var foos: [Foo].
Also if I change Bar to this, then I lose conformance to Codable:

struct Bar: Codable, BarProtocol { // ❌ Type 'Bar' does not conform to protocol 'Decodable'
    var foos: [FooProtocol]
}

I found one way to get Bar to conform to both protocols like this:

struct Bar: Codable, BarProtocol {
    var _foos: [Foo]
    var foos: [FooProtocol] { return _foos }
}

Is there another way to achieve that without using that intermediary _foo property?
Maybe by changing something inside Bar implementation, or maybe inside the BarProtocol declaration?

Thank you.

One way to make it work is to not use existentials and give BarProtocol an associated type instead:

public protocol BarProtocol {
    associatedtype FooType: FooProtocol
    var foos: [FooType] { get }
}

This then requires your load function to become generic (at least until SE-0309: Unlock existentials for all protocols lands):

public func load<BarType: BarProtocol>(bar: BarType) {
    for foo in bar.foos { /* ... */ }
}

This makes your code compile. Whether it’s a workable solution for you is another question and depends on how you intend BarProtocol to be used.

2 Likes

I followed your advice and made it generic. Thank you for your help!

1 Like
Terms of Service

Privacy Policy

Cookie Policy