Amos Joshua
Amos Joshua

Reputation: 1753

Encode an array of items conforming to an Encodable protocol

I was surprised recently to find that this:

protocol A: Encodable {}

class B: A {
    var x = 3
}

class C: A {
    var y = 4
}

let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items)

Fails in Swift with:

Type 'any A' cannot conform to 'Encodable'

while this works:

let items: [B] = [B()]
let encoded = try JSONEncoder().encode(items)

Apparently the issue is that protocols do not conform to themselves. A workaround is provided in this answer.

I understand the reasoning and the workaround in the answers, but it is still quite inconvenient. Both of those answers are from ~2017; is there a cleaner way to solve this in swift 5?

Upvotes: 2

Views: 468

Answers (2)

Adrian Bobrowski
Adrian Bobrowski

Reputation: 2794

Sample workaround :)

struct AnyEncodable: Encodable {
    
    let item: any Encodable
    
    func encode(to encoder: any Encoder) throws {
        var container = encoder.singleValueContainer()
        try container.encode(self.item)
    }
}

let items: [A] = [B()]
let encoded = try JSONEncoder().encode(items.map { AnyEncodable(item: $0) })

Upvotes: 3

vadian
vadian

Reputation: 285072

encode(_:) is a generic method which takes a concrete static type conforming to Encodable. The generic design of the method is the reason why you cannot use the protocol itself. The compiler needs to know the structure of the static type to be able to synthesize the protocol method encode(_:).

Encode an array of items conforming to an Encodable protocol

is fine, but you are trying to

Encode an array of items being the Encodable protocol

which is impossible. This is valid since 2017 till today.

Upvotes: 0

Related Questions