<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div><blockquote type="cite" class=""><div class="">On Apr 12, 2017, at 11:44 AM, Russ Bishop via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><br class=""></div><div class="">* String and Int keys being optional, giving a CodingKey the opportunity to return nil for both at runtime.</div></div></div></blockquote><div><br class=""></div><div>This was true in the first public draft, but I believe in this version `stringValue` is no longer Optional.</div><br class=""><blockquote type="cite" class=""><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">* Encoder has three functions, but only one may ever be called. This API is the opposite of "pit of success".</div><div class=""></div></div></div></blockquote><div><br class=""></div><div>Personally, I'm worried about that too. But I had a lot of trouble coming up with an alternative that didn't violate a more important goal, like "being able to throw errors" or "being compatible with classes".</div><div><br class=""></div><div>Last-ditch suggestion: Change a bunch of names so that, for instance, `Encoder` is instead `EncodingContainerizer`. (That's a terrible name, but "Factory" gives me the hives.) That way, the name of the type gives you a hint that you're supposed to use it to make a container. You might even rename the methods to e.g. `useContainer(keyedBy:)`, which sound a little more stateful and mutually-exclusive.</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>func encode(to encoder: EncodingContainerizer) throws {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>var container = encoder.useContainer(keyedBy: CodingKeys.self)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>try&nbsp;container.encode(name, forKey: .name)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>try&nbsp;container.encode(birthDate, forKey: .birthDate)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">I don't understand why KeyedEncodingContainer needs all those overloads; automatic conformance to Encodable should be provided for the stdlib types in those overloads so why would they be necessary?</div><div class=""><div class=""></div></div></div></blockquote><div><br class=""></div><div>I argued about this pretty vigorously. They want to avoid the overhead of building an encoder and single-value container and then making several generic calls to encode the value into the container. Personally, I think this is premature optimization of the highest order—particularly since building an encoder and single-value container are often no-ops—but this is the design they chose, and I don't think it's worth rejecting for that alone.</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><div class="">KeyedEncodingContainer.encodeWeak seems like it should be a protocol refinement so you can check for the capability (or potentially know at compile time).</div></div></div></blockquote><div><br class=""></div><div>This probably ends up duplicating not only `KeyedEncodingContainerProtocol`, &nbsp;but also `UnkeyedEncodingContainer`, `Encoder`, and `Encodable`. Doable, yes. Worth it, especially when `encodeWeak` has a pretty sensible fallback behavior? Eh.</div><br class=""><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><div class="">(One minor bit of bike shedding: decode/decodeIfPresent could instead be decode(required:) and decode(optional:)).</div><div class=""></div></div></div></blockquote><div><br class=""></div><div>I don't think `required:` and `optional:` are really helpful. The name here is kind of like `addingWithOverflow(_:_:)`—you really want it to be `adding(x, y, .withOverflow)`, but it's not worth creating a dummy enum just to make a method read properly. Similarly, you'd like `decode(Int.self, .ifPresent)`, but the dummy's not worth the better readability.</div><div><br class=""></div><div>I'm not sure why we don't do this, though:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>// Just showing Unkeyed for simplicity</div><div><span class="Apple-tab-span" style="white-space:pre">        </span></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>func decode&lt;T: Decodable&gt;(_ type: T.Type) throws -&gt; T</div><div><div><span class="Apple-tab-span" style="white-space: pre;">        </span>func decode&lt;T: Decodable&gt;(_ type: Optional&lt;T&gt;.Type) throws -&gt; T?</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>let alwaysInt = try&nbsp;container.decode(Int.self)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>let maybeInt = try container.decode(Int?.self)</div><div class=""><br class=""></div></div><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class=""><div class="">I really strongly dislike mixing up the Unkeyed and Keyed concepts. A type should need to explicitly opt-in to supporting unkeyed and that should be enforced at compile time. Unkeyed encoding is a potential versioning nightmare and should be handled with care.</div></div></div></blockquote><div><br class=""></div><div>I think they've done a reasonable job of putting unkeyed coding in a sharps drawer by making you specifically ask for it and giving it an ugly name.&nbsp;</div><div><br class=""></div><blockquote type="cite" class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><div class="">C#'s serialization attributes are a better and more comprehensive solution but we don't have custom attributes in Swift and property behaviors were deferred. This problem is too important to leave to the future though. If we did ever add custom attributes or if property behaviors get implemented then this design could adopt them incrementally without breaking compatibility (e.g. a serialization transformer behavior that turns a non-Encodable property into an Encodable one, or a behavior that ignores a property for serialization purposes).</div></div></blockquote><br class=""></div><div>On the contrary, I think we *can* safely leave this to the future. If a future version of Swift and Foundation added:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>@uncoded var foo: Bar</div><div><br class=""></div><div>That would be a completely additive change. Until then, there's an irritating but serviceable solution available—write your own CodingKeys enum and let code generation write the `Codable` conformances based on it.</div><br class=""><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-east-asian: normal; font-variant-position: normal; line-height: normal; border-spacing: 0px;"><div class=""><div style="font-size: 12px; " class="">--&nbsp;</div><div style="font-size: 12px; " class="">Brent Royal-Gordon</div><div style="font-size: 12px; " class="">Architechies</div></div></span>

</div>
<br class=""></body></html>