<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 Mar 17, 2017, at 2:38 PM, Matthew Johnson &lt;<a href="mailto:matthew@anandabits.com" class="">matthew@anandabits.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><blockquote type="cite" class="" style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-size-adjust: auto; -webkit-text-stroke-width: 0px;"><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class="">At a broad level, that's a good idea. But why not provide something more precise than a bag of `Any`s here? You're in pure Swift; you have that flexibility.</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>protocol Codable {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>associatedtype CodingContext = ()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>init&lt;Coder: Decoder&gt;(from decoder: Coder, with context: CodingContext) throws</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encoder&lt;Coder: Encoder&gt;(from encoder: Coder, with context: CodingContext) throws</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>protocol Encoder {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>associatedtype CodingContext = ()</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func&nbsp;container&lt;Key&nbsp;:&nbsp;CodingKey&gt;(keyedBy&nbsp;type:&nbsp;Key.Type)&nbsp;-&gt;&nbsp;KeyedEncodingContainer&lt;Key, CodingContext&gt;</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>class KeyedEncodingContainer&lt;Key: CodingKey, CodingContext&gt; {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode&lt;Value: Codable&gt;(_ value: Value,? forKey key: Key, with context: Value.CodingContext) throws { … }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>// Shorthand when contexts are the same:</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode&lt;Value: Codable&gt;(_ value: Value,? forKey key: Key) throws</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>where Value.CodingContext == CodingContext</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>{ … }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span></div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>…</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">        </span>}</div></div></div></blockquote><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">This is sort of similar to the design I suggested for contexts. &nbsp;The difference is that you’re requiring all Codable to be context aware and by introducing an associated type you break the ability to use Codable as an existential.</div></div></div></div></blockquote><div><br class=""></div><div>I don't think banning existentials is actually a loss. Since `encode(_:)` doesn't record type information, and instead `decode(_:)` requires the exact concrete type to be passed in, `Codable` existentials cannot be usefully encoded or decoded. For instance, a heterogeneous `[Codable]` would encode in several different, probably mutually incompatible formats, without any type information that could distinguish between them. Since the only semantics of `Codable` are encoding and decoding, and decoding is always done by an `init`, `Codable` existentials are useless and we lose nothing by not supporting them.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Many Codable conforming types won’t need to know anything about a context. &nbsp;I would still want to be able to encode them along with my custom context-aware types. &nbsp;A good example is types from Foundation that will conform to Codable. &nbsp;They will definitely not know anything about my context but I still want to be able to encode a URL alongside my custom context-aware types.</div><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class=""></div></div></div></div></blockquote><div><br class=""></div><div>Sure; you can do that by calling `encode(_:forKey:with:)` and passing a freshly-made `()` context. We might even add a second convenience overload of `encode(_:forKey:)`:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>class KeyedEncodingContainer&lt;Key: CodingKey, CodingContext&gt; {<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func encode&lt;Value: Codable&gt;(_ value: Value,? forKey key: Key, with context: Value.CodingContext) throws { … }<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span><br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>// Shorthand when contexts are the same:<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func encode&lt;Value: Codable&gt;(_ value: Value,? forKey key: Key) throws<br class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>where Value.CodingContext == CodingContext<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>{</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>try encode(value, forKey: key, with: currentContext)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">                </span></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>// Shorthand when the type uses a Void context:</div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>func encode&lt;Value: Codable&gt;(_ value: Value,? forKey key: Key) throws<br class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>where Value.CodingContext == Void<br class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>{</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>try encode(value, forKey: key, with: ())</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">                </span><br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>…<br class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}<br class=""><br class=""></div><div>The main disadvantage I can think of in this design is that even `Codable` users who don't need a context have to have a `with context: Void` in their code. This might be confusing to new developers, but I think it's worth it.</div><div><br class=""></div><div>(I don't think I mentioned this anywhere, but containers like `Array` should take on the `CodingContext` of their `Element`s and pass the context they receive through without examining it. That would probably be pretty common with generic container types.)</div><br class=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;"><div class=""><div style="font-family: Helvetica; font-size: 12px; font-style: normal; font-variant-caps: normal; font-weight: normal; letter-spacing: normal; orphans: auto; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; widows: auto; word-spacing: 0px; -webkit-text-stroke-width: 0px;" class="">Did you take a look at the design I suggested? &nbsp;What do you think of it?</div></div></div></div></blockquote><div><br class=""></div>I think that, if a type wants to support context-free coding, it should use an optional `CodingContext`. :^)</div><div><br class=""></div><div>In all seriousness, I see the design as very slightly weak, in that it makes it easy to forget to pass a context through, but quite acceptable. It would certainly solve the `with context: Void` problem I mentioned. I might consider reversing the relationship between the two protocols, though:</div><div><br class=""></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public protocol ContextAwareCodable {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>associatedtype CodingContext</div><div><span class="Apple-tab-span" style="white-space:pre">                </span></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>init(from decoder:&nbsp;Decoder, with context: CodingContext)&nbsp;throws<br class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func&nbsp;encode(to encoder:&nbsp;Encoder, with context: CodingContext)&nbsp;throws</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>public protocol Codable: ContextAwareCodable where CodingContext == Void {</div><div><div><span class="Apple-tab-span" style="white-space: pre;">                </span>init(from decoder:&nbsp;Decoder)&nbsp;throws<br class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func&nbsp;encode(to encoder:&nbsp;Encoder)&nbsp;throws</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>extension Codable {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>public init(from decoder:&nbsp;Decoder, with context: Void)&nbsp;throws {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>try&nbsp;self.init(from: decoder)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func&nbsp;encode(to encoder:&nbsp;Encoder, with context: Void)&nbsp;throws {</div></div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>try encode(to: encoder)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div><br class=""></div><div>Most `Encoder`/`Decoder` APIs would have to use `ContextAwareCodable`, but if you're writing a coder, you'd better be aware of contexts.</div><div><br class=""></div><div>* * *</div><div><br class=""></div><div>A thought I just had: Someone upthread mentioned that `Codable` might be better as part of the standard library. One reason to favor that approach is that you could then make `Codable` support a requirement of types like `BinaryInteger` and `FloatingPoint`.</div><div><br class=""></div><div>It might still make sense to have the coders themselves be part of Foundation; only the protocols defining `Codable`, `Encoder`, `Decoder`, and their ancillary types would be part of the standard library.</div><br class=""><div class="">
<span class="Apple-style-span" style="border-collapse: separate; font-variant-ligatures: normal; font-variant-position: normal; font-variant-numeric: normal; font-variant-alternates: normal; font-variant-east-asian: 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>