# SE-0295: Codable synthesis for enums with associated values (second review)

**URL:** <https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036>\
**Category:** Proposal Reviews\
**Created:** [January 21, 2021, 4:43pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036 "2021-01-21T16:43:11Z")\
**Posts on this page:** 14\
**Page:** 2

<div class="post-metadata">

**Author:** ![jayton](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jayton/32/5592_2.png) [@jayton](https://forums.swift.org/u/jayton)\
**Post date:** [January 25, 2021, 9:25am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/21 "2021-01-25T09:25:04Z")

</div>

> [@woolsweater](#):
>
> Along with everything else that's been said, the chosen encoding is highly ambiguous; unless I am misreading, these two have identical encodings!
> 
> ```swift
> enum E { case a(Bool), b([Int]) }
> enum F { case a, b(UInt8, UInt8, UInt8) }
> 
> ```
> 
> That kind of thing is a trap laid waiting for a program ingesting serialized data even from a nominally trusted source.

I’m generally dubious about this proposal for reasons that have already been stated, but this isn’t an actual problem. Codable is designed for duck-typed serialization formats; the fact that one representation can map to multiple types is inherent. For example, `3` in JSON might be decoded as an `Int` or a `Double`, while `"http://example.com/"`can be decoded as a `String` or a `URL`.

In this case, `E` is more general than `F`; an encoded `E` should be decodable as an `F` if it happened to have three integers in the range 0...255, and not otherwise.

---

<div class="post-metadata">

**Author:** ![Max\_Desiatov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/max_desiatov/32/20654_2.png) [@Max\_Desiatov](https://forums.swift.org/u/Max_Desiatov)\
**Post date:** [January 25, 2021, 9:42am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/22 "2021-01-25T09:42:20Z")

</div>

> [@gwendal.roue](#):
>
> Considering that there exists apis that do not provide easy access to some inner raw `Decoder` and `Encoder` instances, a static property might be a better choice.

I hope that any new additions to `Codable` would avoid the strategies pattern. In my experience it has proven to be critically inflexible, even when a strategy is set up per encoder/decoder instance, not a static property.

It's relatively frequent for APIs to return dates in different formats even for different properties of the same entity, or for different entities. With strategies it's very cumbersome to customize coding per property or per type. The strategies pattern could have made sense when `Codable` was designed (what was it? Swift 2? Swift 3?), but right now in 2021 property wrappers are a much better approach in my opinion (see the [BetterCodable](https://github.com/marksands/BetterCodable) library).

Now when reading your code again, I see that static property is defined on the codable type itself, I still think it's relatively cumbersome. While property wrappers can't be attached to enum cases or associated values, I wonder if there could be a better way to specify customizations with them for this case.

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [January 25, 2021, 9:55am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/23 "2021-01-25T09:55:51Z")

</div>

> [@Max\_Desiatov](#):
>
> The strategies pattern could have made sense when `Codable` was designed (what was it? Swift 2? Swift 3?), but right now in 2021 property wrappers are a much better approach in my opinion (see the [BetterCodable](https://github.com/marksands/BetterCodable) library).

I agree this is a real question, and that years have shaped our experience of Codable. You can see the [follow-up question](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/20), and I'm very interested in the point of view of the designers of Codable, who did a _tremendous_ job. On the topic of property wrappers: they sure are handy. But don't they have their own limitations? For example, since they are usually embedded as a property of a container type, how can we deal with a top-level value?

---

<div class="post-metadata">

**Author:** ![Max\_Desiatov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/max_desiatov/32/20654_2.png) [@Max\_Desiatov](https://forums.swift.org/u/Max_Desiatov)\
**Post date:** [January 25, 2021, 9:56am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/24 "2021-01-25T09:56:07Z")

</div>

> [@gwendal.roue](#):
>
> Codable was designed in order to decouple the coding format from the Codable types.

And yet, sadly, the proposal and both review threads focused mostly if not exclusively on JSON. 😔

> [@gwendal.roue](#):
>
> Customization, when possible, is only available via decoder or encoder instances ( `userInfo` , or properties as in Foundation encoders). In my previous message, I'm suggesting that the enum type itself becomes responsible for its formatting, and this clearly goes against the initial design choices. Hence this genuine question :-)

I agree that setting these properties on coder instances is probably right in principle for complete separation of "model" types and coding formats. And yet, I don't see it working really well in practice. Especially when there's a need to customize a single property of a single type in a deeply nested tree of coded entities. In my practice this is much more common than sharing the same codable type between multiple target formats

Doing that with the current strategies implementation is incredibly cumbersome. Your approach with a static property on codable types is actually much better from this perspective.

---

<div class="post-metadata">

**Author:** ![gwendal.roue](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/gwendal.roue/32/13992_2.png) [@gwendal.roue](https://forums.swift.org/u/gwendal.roue)\
**Post date:** [January 25, 2021, 10:45am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/25 "2021-01-25T10:45:09Z")

</div>

> [@Max\_Desiatov](#):
>
> Doing that with the current strategies implementation is incredibly cumbersome. Your approach with a static property on codable types is actually much better from this perspective.

Thank you ;-) But I wouldn't want anyone to think that I'm keen to throw a _core design decision_ about Codable away, and call it a day. Since the beginning, the language, the standard library, and Foundation have spoken together with a single voice. We can't introduce a discordant api lightly, because the consequences of a paradigm schism are difficult to foresee.

---

<div class="post-metadata">

**Author:** ![itaiferber](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/itaiferber/32/33840_2.png) [@itaiferber](https://forums.swift.org/u/itaiferber)\
**Post date:** [January 25, 2021, 2:44pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/26 "2021-01-25T14:44:15Z")

</div>

> [@gwendal.roue](#):
>
> I wonder what @itaiferber thinks about this sentence.

There are a few things to unpack in this thread, so I hope I manage to get them all.

Not a direct response to what you wrote, but for context: I think it's important to call out that what this pitch is proposing is a strategy for `Codable` _synthesis_ for enums, so we're talking about compile-time behavior and not necessarily runtime behavior (which is separate, and not incompatible). In scope, we're looking at a way to influence how a _type_ implements `init(from:)` and `encode(to:)`, and are not able to influence how a _property_ encodes — property wrappers (and strategies) are a nice solution, but out of scope here.

To discuss _synthesis_ specifically — a while back [I had a similar suggestion](https://forums.swift.org/t/automatic-codable-conformance-for-enums-with-associated-values-that-themselves-conform-to-codable/11499/13), along slightly different lines:

> [@Automatic Codable conformance for enums with associated values that themselves conform to Codable](https://forums.swift.org/t/automatic-codable-conformance-for-enums-with-associated-values-that-themselves-conform-to-codable/11499/13):
>
> For instance, one straw-man approach to this is to generate both implementations and allow someone to use either approach via a property, e.g.
> 
> ```swift
> enum SynthesizedEnumDiscriminatorType {
> // No discriminator -- attempt cases in order single-value
> case none
> 
> // Use the case name as the value-containing key, e.g.
> // {"album": {"id": "abc"}} or {"podcast": {"id": "xyz"}}
> case discriminateByCaseName
> 
> // Use the case name as a discriminator keyed by the given key, e.g.
> // with disciminateByCaseNameForKey(CodingKeys.object), {"object": "album", "id": "abc"}
> case discriminateByCaseNameForKey(CodingKey)
> }
> 
> enum MyEnum {
> case string(String)
> case double(Double)
> 
> // Synthesized
> static var codableDiscriminatorType: SynthesizedEnumDiscriminatorType {
> return .none
> }
> 
> init(from decoder: Decoder) throws {
> switch MyEnum.codableDiscriminatorType {
> // ... use the strategies
> }
> }
> }
> 
> ```
> 
> Essentially, add another customization point by using a property similar to how `CodingKeys` influences the representation of a structured type. If you want to override the discriminator strategy used, provide a discriminator type via the enum (you can even make it mutable if we decide to generate all implementations and choose dynamically).

Given that enums span a wide range of use cases, I've always been in favor of offering customization for those use-cases. The (understandable) lack of consensus among how folks would prefer an enum encode was something that always prevented an easy implementation of this feature, and while I sympathize with the desire to get _a_ default in place, I wish the pitch called this out a little more explicitly.

A `static` property would give us an "in" to inform the compiler of how you might expect the enum to encode and decode, in the same way that `CodingKeys` allow us to inform the compiler of expected synthesis for structural types.

So, my thoughts on this are: given thoughtful design of what customization options are possible, I'm obviously in favor. This design would effectively depart entirely from the pitch, which is, of course, entirely out of my hands.

Now, this design gives customization for a _compile-time implementation_ of `init(from:)`/`encode(to:)`, but that is entirely orthogonal to runtime overrides on an encoder/decoder or property level. Individual encoders and decoders _could_ look for some info in `.userInfo` to override specific types (already possible today, done on a type-by-type basis with buy-in from the encoder/decoder), and property wrappers can be written to override `enum` properties. These are already possible today, though, and still require an existing `Codable` implementation, which the pitch intends to offer a default for.

* * *

A few unrelated thoughts on some things called out here:

- Edge cases not covered by the pitch, such as `case bar(number: Int, number: Int, number: String)`, `case barbar(Void, (Void, Void))`, and others: enums offer a surface area that other structural types do not (e.g. you can't have overloaded property names on a struct, but you can have repeated labels), and I think that regardless of future directions, we can come up with solutions to these, either by defining behavior, or preventing synthesis. Either way, it'd be nice to collect these edge cases in the proposal and explicitly call out what is to be done in each case

- For "ambiguous" encoding of something like

- For historic reference, `Codable` was released with Swift 4:

---

<div class="post-metadata">

**Author:** ![hisekaldma](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/hisekaldma/32/1146_2.png) [@hisekaldma](https://forums.swift.org/u/hisekaldma)\
**Post date:** [January 25, 2021, 6:35pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/27 "2021-01-25T18:35:02Z")

</div>

-1. I’m still of the opinion that if Swift is going to embrace a single default for encoding enums a [”case as value” approach](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values/42408/47) is a better default than a ”case as key” approach. The changes to the proposal since the first review don’t really change that. (And some great arguments have been made both in this thread and the previous thread that we in fact shouldn’t embrace a single default approach, but rather make it something that the user must choose explicitly.)

However, since the core team has specifically asked for input on the updated proposal from a schema evolution standpoint, I want to do a deep dive on that. Regardless of what approach we adopt, I think the out-of-the-box behavior should support changing schemas in backward/forward compatible ways as much as possible. If you slap `Codable` on an enum, you should get something that you can use immediately, but it should also be something that you can change when you have data or clients out there using it. And the proposed format is not it.

It’s a common principle when evolving schemas that _adding a member with a default value is a backwards compatible change_. In the proposed format, _this isn’t generally true for associated values_.

Let’s look at some scenarios in detail:

## A. Adding an unlabeled value to a case without associated values

🚫 Not backwards compatible. The container doesn't change, but the value changes from a `Bool` to whatever type the associated value is. Data encoded with the old version will (probably?) throw if decoded with the new version.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test
}

```

 | 

```json
{
  "test": true
}

```

 |
| New | 

```swift
enum E {
  case test(Double = 0.0)
}

```

 | 

```json
{
  "test": 2.0
}

```

 |

## B. Adding an unlabeled value to a case with a single unlabeled value

🚫 Not backwards compatible. The container changes from a single value container to an unkeyed container, so data encoded with the old version will throw if decoded with the new version.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(Int)
}

```

 | 

```json
{
  "test": 1.0
}

```

 |
| New | 

```swift
enum E {
  case test(Int, Double = 0.0)
}

```

 | 

```json
{
  "test": [1.0, 2.0]
}

```

 |

## C. Adding an unlabeled value to a case with multiple unlabeled values

⚠ Maybe backwards compatible. It depends on whether the synthesized `init(from:)` handles unkeyed containers with fewer elements than expected when some or all associated values have default values. The behavior here is unspecified in the proposal, so it’s hard to tell.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(Int, Int)
}

```

 | 

```json
{
  "test": [1.0, 1.0]
}

```

 |
| New | 

```swift
enum E {
  case test(Int, Int, Double = 0.0)
}

```

 | 

```json
{
  "test": [1.0, 1.0, 2.0]
}

```

 |

## D. Adding an unlabeled value to a case with labeled values

🚫 Not backwards compatible. The container changes from a keyed container to an unkeyed container, so data encoded with the old version will throw if decoded with the new version.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(name: String)
}

```

 | 

```json
{
  "test": {
    "name": "abc"
  }
}

```

 |
| New | 

```swift
enum E {
  case test(name: String, Double = 0.0)
}

```

 | 

```json
{
  "test": ["abc", 2.0]
}

```

 |

## E. Adding a labeled value to a case without associated values

🚫 Not backwards compatible. The container changes from a single value container to an keyed container, so data encoded with the old version will throw if decoded with the new version.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test
}

```

 | 

```json
{
  "test": true
}

```

 |
| New | 

```swift
enum E {
  case test(name: String = "")
}

```

 | 

```json
{
  "test": {
    "name": "abc"
  }
}

```

 |

## F. Adding a labeled value to a case with a single unlabeled value

🚫 Not backwards compatible. The container changes from a single value container to an unkeyed container, so data encoded with the old version will throw if decoded with the new version.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(Int)
}

```

 | 

```json
{
  "test": 1.0
}

```

 |
| New | 

```swift
enum E {
  case test(Int, name: String = "")
}

```

 | 

```json
{
  "test": [1.0, "abc"]
}

```

 |

## G. Adding a labeled value to a case with multiple unlabeled values

⚠ Maybe backwards compatible. It depends on whether the synthesized `init(from:)` handles unkeyed containers with fewer elements than expected when some or all associated values have default values. The behavior here is unspecified in the proposal, so it’s hard to tell.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(Int, Int)
}

```

 | 

```json
{
  "test": [1.0, 1.0]
}

```

 |
| New | 

```swift
enum E {
  case test(Int, Int, name: String = "")
}

```

 | 

```json
{
  "test": [1.0, 1.0, "abc"]
}

```

 |

## H. Adding a labeled value to a case with labeled values

✅ Backwards compatible.

| | Swift | JSON |
| Old | 

```swift
enum E {
  case test(name: String)
}

```

 | 

```json
{
  "test": {
    "name": "abc"
  }
}

```

 |
| New | 

```swift
enum E {
  case test(name: String, category: String = "")
}

```

 | 

```json
{
  "test": {
    "name": "abc",
    "category": "things"
  }
}

```

 |

These scenarios highlight a couple of things:

1. **Changing the type of container based on the payload is a really bad idea from a compatibility standpoint**. The changes in the scenarios above would all be backward compatible if the synthesis always used a keyed container, and used `"$0"` or `"_0"` as keys for the unlabeled values, as has been suggested multiple times.

2. **There is no underlying principle or general rule for which changes you can make to enums and maintain backward compatibility** with the proposed format. In the previous version, you could at least go by ”adding a labeled value is always backward compatible”, but now that cases without associated values are encoded as `true`, even that doesn’t work.  
  
In fact, if you’re working on something where backwards compatibility is an absolute must, the only sound advice seems to be ”if an enum has associated values, always implement `Codable` manually.” I can definitely see that becoming a lint rule in some projects.

3. **The proposal still doesn’t specify how the synthesis will actually work in enough detail** (e.g. how does decoding of unlabeled values with default values work?).

---

<div class="post-metadata">

**Author:** ![Drew\_Crawford1](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/drew_crawford1/32/11959_2.png) [@Drew\_Crawford1](https://forums.swift.org/u/Drew_Crawford1)\
**Post date:** [January 25, 2021, 7:03pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/28 "2021-01-25T19:03:25Z")

</div>

I am -1 on this proposal as written for reasons [best expressed](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/10) by @Max_Desiatov, this is not widely applicable enough to be a default.

I **do** feel the solution is strong enough we should ship it as an **option**. @sveinhal [discusses](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/18) how to use `strateg`ies to pick between these sorts of option, which at a very high level seems like the right approach to me, although since `strategy` is a runtime API configured at the decoder level this has many practical limitations.

However if the goal is to configure the autosynthesis at the **type** level, a natural way might be `struct Foo: CaseAndValuesCodable { ... }`. Alternatively, a "type wrapper" like `@CaseAndValuesCodable struct Foo { ... }` could work. (We'd implement `@CaseAndValuesCodable` like a builtin attribute now, but someday you could write your own typewrapper and get your own autosynthesis flavor, and we could continue to consider new builtin flavors in new proposals).

IMO getting some consensus around shipping this as an option and how like options are specified would be the best way to move this proposal forward.

---

<div class="post-metadata">

**Author:** ![aerobounce](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/aerobounce/32/14175_2.png) [@aerobounce](https://forums.swift.org/u/aerobounce)\
**Post date:** [January 27, 2021, 7:56am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/29 "2021-01-27T07:56:19Z")

</div>

-1 if the proposal would be accepted without modification.

Although I +1 ed before in this thread, seeing people's opinions and points, and re-reading the proposal again and again, now -1.

#### Some opinions observing ideas posted by people

* * *

### Drop support for unnamed value

- Given CodingKeys is auto-synthesized, it doesn't have to support cases that contain unnamed value. If it doesn't support unnamed value, discussion may go forward since we don't have to define what default style it should be. First of all, I don't see a big benefit supporting it personally.
- If unnamed value have to be supported, default style has to be defined - and currently there is no single style that everybody agrees nor likely there will be in the future. That kind of architecting should be left to end users. In other words those should be implemented by individuals.
- And I suggest discussing about unnamed value to be Codable in the other pitch/proposal, if needed.

* * *

### Drop support for repeated named value

- A case such as below should not be supported.

```swift
enum Foo {
    case bar(number: Int, number: Int, number: String)
}

```

* * *

### Support only associated values whose are `Codable`

- If a case contains a value type such as `Void`, that should not be supported.
- If, types whose are not `Codable` become `Codable` only when it's enum's an associated value... — That does not make sense and confusing.

* * *

### Drop support for an enum case without associated values / mixed cases

- We don't have one concrete idea for this just like unnamed value doesn't.
- If this have to be implemented, then that should be discussed in the other pitch or proposal as well, as this proposal states `enums with associated values`.
- I guess this had to be included in the proposal since it's quite easy to imagine enums with mixed cases (case with values and simple case without any values)

* * *

Briefly dividing, there are problems like:

1. How to handle unnamed value
2. How to handle enum with mixed cases (one with value, other without)
3. How to handle a case has values whose are not `Codable` already

I'm starting to feel that that's too much for one proposal to define them all.

* * *

I'm basically suggesting to make it like `struct` conformed to `Codable`, by dropping features what `struct Example: Codable` cannot do.  
I think, basically, situations that classes or structs cannot conform to `Codable` should not be supported in this proposal neither.

So, IMO:

### enum with associated values should be Codable only when:

- Every associated values in an enum conform to `Codable`
- Every associated values in an enum are named / labeled
- Associated value names in a case must not be duplicated / repeated
- An enum must not have a case without associated values (every cases must have associated values)

---

<div class="post-metadata">

**Author:** ![wowbagger](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/wowbagger/32/13847_2.png) [@wowbagger](https://forums.swift.org/u/wowbagger)\
**Post date:** [January 27, 2021, 8:56am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/30 "2021-01-27T08:56:47Z")

</div>

> [@aerobounce](#):
>
> If a case contains a value type such as `Void` , that should not be supported.

I assume this is in some way related to this edge case I posted upthread:

```swift
enum Foo {
    case bar(Void)
    case barbar(Void, (Void, Void))
}

```

I should've clarified that the edge here is that `case bar(Void)`, `case bar()`, and `case bar` are practically the same thing. Given how similar associated values are with tuples, and since tuples like `(Void)` and `()` are treated the same in some places with tuple splat, I find it worth discussing how `Codable` synthesis for enums should handle it.

---

<div class="post-metadata">

**Author:** ![jayton](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jayton/32/5592_2.png) [@jayton](https://forums.swift.org/u/jayton)\
**Post date:** [January 27, 2021, 9:17am UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/31 "2021-01-27T09:17:03Z")

</div>

I think it’s simpler than that: those cases shouldn’t be supported because `Void` is not `Codable`. If `Void` (and other tuples) were codable, the representation of the enum would follow from the representation of the tuples.

Special rules for `Void` would be a bad idea, and a bit silly since there are few if any non-generic uses of `Void` associated values. For generic cases, special rules wouldn’t work:

```swift
enum Bloptional<T> {
    case some(T)
    case none
}

// This kind of extension (in the same module) works for structs
extension Bloptional: Codable where T: Codable {}

```

`Bloptional<Void>` can’t have special behaviour in Swift’s generic model; its behaviour must be a composition of the `Codable` behaviour of `Bloptional` with the (hypothetical) `Codable` behaviour of `Void`.

Realistically, if tuples are extended with conditional `Codable` support they will be represented as unkeyed containers, and the representation for `Void` will be equivalent to `[]` while `(Void, Void)` will be equivalent to `[[], []]`.

---

<div class="post-metadata">

**Author:** ![drexin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/drexin/32/7573_2.png) [@drexin](https://forums.swift.org/u/drexin)\
**Post date:** [January 27, 2021, 7:07pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/32 "2021-01-27T19:07:26Z")

</div>

Thanks for your feedback!

> [@wowbagger](#):
>
> Strong -1, for the following reasons:
> 
> 1. The proposal only proposes the solution in terms of JSON, instead of containers. Although the implementation uses containers, it's the written proposal we are evaluating here. It's impossible to for me to agree with the proposal without seeing discussions on encoding/decoding for other serialisation formats.

JSON is being used for the examples because it's one of the most widely used formats and easily readable. The wording in the text should have been along the lines of Codable, I agree, but the JSON types map directly to the respective containers in Codable.

Related: @Max_Desiatov do you have any specific examples of formats that would not work with this proposal? Since everything here uses the standard Codable interface, I would be surprised if anything in this proposal specifically would cause compatibility issues that are not already observable.

> [@wowbagger](#):
>
> 1. The proposal has no discussion about enum cases with repeated labels:

The above example is not valid in Swift. It is currently possible to define this case because of a compiler quirk, you will however get a compiler error when you are trying to create the value. From 5.4 onwards even the definition will cause a compile error.

> [@wowbagger](#):
>
> 1. The proposal does not address some other edge cases such as `Void` associated values:

As @jayton already mentioned, `Void` does not conform to `Codable` and it it were, the format would be defined by that conformance and is not relevant for this proposal.

> [@wowbagger](#):
>
> 1. The proposed solution for enum cases without associated values is actively harmful, because it's both surprising and confusing:

I agree that the format is not great. In the original proposal it was `{}`, but I received feedback that `true` would be less biased.

---

<div class="post-metadata">

**Author:** ![Max\_Desiatov](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/max_desiatov/32/20654_2.png) [@Max\_Desiatov](https://forums.swift.org/u/Max_Desiatov)\
**Post date:** [January 27, 2021, 7:27pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/33 "2021-01-27T19:27:47Z")

</div>

> [@drexin](#):
>
> Related: @Max_Desiatov do you have any specific examples of formats that would not work with this proposal? Since everything here uses the standard Codable interface, I would be surprised if anything in this proposal specifically would cause compatibility issues that are not already observable.

My point is not that it wouldn't work at all, but rather that the proposed default synthesized conformance doesn't necessarily make sense for all formats. Consider this XHTML:

```xml
<table>
  <tr>
    <th>A0</th>
    <td>B0</td>
  </tr>
  <tr>
    <td>A1</td>
    <td>B1</td>
  </tr>
  <tr>
    <td>A2</td>
    <td>B2</td>
  </tr>
</table>

```

I hope that a "natural" `Codable` model type for it would look like this:

```swift
struct Table: Codable {
  let tr: [TableRow]
}

struct TableRow: Codable {
  let cells: [Cell]
}

enum Cell: Codable {
  case th(String)
  case td(String)
}

```

I don't think that this proposal allows for that. But this is only my inference from the current proposal text. Instead of giving examples of the synthesized `Codable` conformance code, or explaining what would happen in terms of keyed and unkeyed containers, with only JSON examples provided I can only guess what would (or would not) happen when/if the implementation lands.

Additionally, with XML we need a way to specify which keys are encoded as attributes, and which as elements. We can already do that for structs [with property wrappers](https://twitter.com/maxdesiatov/status/1354388206175870977), but is there a way to implement this for enums at all? Is this even considered as a future direction? I don't see how the proposal as written can be expanded in the future to allow this.

---

<div class="post-metadata">

**Author:** ![drexin](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/drexin/32/7573_2.png) [@drexin](https://forums.swift.org/u/drexin)\
**Post date:** [January 27, 2021, 9:14pm UTC](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036/34 "2021-01-27T21:14:16Z")

</div>

> [@Max\_Desiatov](#):
>
> > [@drexin](#):
> >
> > Related: @Max_Desiatov do you have any specific examples of formats that would not work with this proposal? Since everything here uses the standard Codable interface, I would be surprised if anything in this proposal specifically would cause compatibility issues that are not already observable.
> 
> My point is not that it wouldn't work at all, but rather that the proposed default synthesized conformance doesn't necessarily make sense for all formats. Consider this XHTML:
> 
> ```xml
> <table>
> <tr>
> <th>A0</th>
> <td>B0</td>
> </tr>
> <tr>
> <td>A1</td>
> <td>B1</td>
> </tr>
> <tr>
> <td>A2</td>
> <td>B2</td>
> </tr>
> </table>
> 
> ```
> 
> I hope that a "natural" `Codable` model type for it would look like this:
> 
> ```swift
> struct Table: Codable {
> let tr: [TableRow]
> }
> 
> struct TableRow: Codable {
> let cells: [Cell]
> }
> 
> enum Cell: Codable {
> case th(String)
> case td(String)
> }
> 
> ```
> 
> I don't think that this proposal allows for that.

`Cell` would encode to `<th>value</th>` and `<td>value</td>` respectively. So I think it does exactly what you want.

> [@Max\_Desiatov](#):
>
> But this is only my inference from the current proposal text. Instead of giving examples of the synthesized `Codable` conformance code, or explaining what would happen in terms of keyed and unkeyed containers, with only JSON examples provided I can only guess what would (or would not) happen when/if the implementation lands.

That is a good point. I will add that to the proposal, thanks.

> [@Max\_Desiatov](#):
>
> Additionally, with XML we need a way to specify which keys are encoded as attributes, and which as elements. We can already do that for structs [with property wrappers](https://twitter.com/maxdesiatov/status/1354388206175870977), but is there a way to implement this for enums at all? Is this even considered as a future direction? I don't see how the proposal as written can be expanded in the future to allow this.

I don't quite understand how this is relevant to this proposal. Property wrappers don't work for associated values, but if they did, they should behave the same as they do on properties today. The wrapper would be passed to `encode(_:)`, which should then invoke the same logic in your encoder as it does for class/struct properties. If you are asking for an alternative way to achieve on enums what you are doing for properties today, I think that is out of the scope of this proposal.

[Previous page](https://forums.swift.org/t/se-0295-codable-synthesis-for-enums-with-associated-values-second-review/44036.md?page=1)
