Codable synthesis for enums in a generic context

In trying out Swift 5.5's Codable synthesis for enums with associated values, I've hit a snag. When contained in a generic type, it isn't clear how to declare conformance. Consider the following:

struct Container<Element>: Codable {
    let options: [Option]
}

extension Container {
    enum Option: Codable {
        case first (Element)
        case second (Element)
    }
}

This produces an error:
Type 'Container.Option' does not conform to protocol 'Encodable/Decodable'.

Hmm, well let's try extracting Codable conformance into its own extension:

extension Container: Codable where Element: Codable {}
extension Container.Option: Codable where Element: Codable {}

Now we get:
generic enum type 'Container.Option' is ambiguous without explicit generic parameters when matching value of type 'Container<Element>.Option'

Since I'm not trying to create a concrete type for Element, I'm not sure what generic parameters are needed in this case. I would assume this should work similar to Equatable conformance:

extension Container: Equatable where Element: Equatable {}
extension Container.Option: Equatable where Element: Equatable {}

This works as expected, so I don't understand what I'm missing with the Codable declaration. Is this intended behavior?

I don't have Swift 5.5 handy, but it seems to me that this should work. If you change Container.Option to a struct, Codable synthesis works in 5.4 at least.

struct Container<Element> {
    let options: [Option]
}

extension Container {
    struct Option {
        var first: Element
        var second: Element
    }
}

extension Container: Codable where Element: Codable {}
extension Container.Option: Codable where Element: Codable {}

Perhaps a workaround might be to move Option outside of Container and make it generic over Element? Like so:

struct Container<Element> {
    let options: [Option<Element>]
}

enum Option<Element> {
    case first (Element)
    case second (Element)
}

extension Container: Codable where Element: Codable {}
extension Option: Codable where Element: Codable {}

Yes, this is reasonable workaround. What you lose with that approach is the 'namespace' isolation. I suppose I could live with it, but it seems like a hole that needs plugging. Appreciate the response!

1 Like

If it works for Equatable, it ought to work for Codable too. This is a beta specific issue, it does work as you'd expect on the main branch. I've filed https://bugs.swift.org/browse/SR-14854 to track the fix being cherry-picked.

3 Likes

Thank you!

Terms of Service

Privacy Policy

Cookie Policy