<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Apr 5, 2017, at 2:29 PM, Brent Royal-Gordon via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class=""><blockquote type="cite" class=""><div class="">On Apr 5, 2017, at 1:44 PM, David Hart via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><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=""><blockquote type="cite" class=""><div class=""><div class="" style="word-wrap: break-word; -webkit-nbsp-mode: space;"><div class=""><div class=""><blockquote type="cite" class=""><div class=""><div class="" 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;"><div class=""><div class=""><div class="">For the same reasons, I continue to believe that decode functions should overload on the return type. If we follow the arguments in favor of providing a type argument, then why don't we also have type arguments for encoders: encode(_ value: T?, forKey key: Key, as type: T.self)? I'm not advocating that: I'm just pushing the argument to its logical conclusion to explain why I don't understand it.</div></div></div></div></div></blockquote><div class=""><br class=""></div>I don’t see a way for a call to encode to become ambiguous by omitting the type argument, whereas the same is not true for a return value from decode. The two seem fundamentally different.</div></div></div></div></blockquote><div class=""><br class=""></div><div class="">When decoding to a property, there will be no ambiguity. And for other cases, Swift developers are already quite used to handling that kind of ambiguity, like for literals:</div><div class=""><br class=""></div><div class="">let x: UInt = 10</div><div class="">let y = 20 as CGFloat</div></div></div></blockquote><br class=""></div><div class="">But in the literal case, they *don't* have to deal with ambiguity for two reasons:</div><div class=""><br class=""></div><div class="">1. The literal provides some hint of the type; integer, float, string, array, and dictionary literals are all easy to distinguish from one another.</div><div class=""><br class=""></div><div class="">2. Each literal syntax has a default type. That is not true and cannot *be* true for `decode()`.</div><div class=""><br class=""></div><div class="">Plus there's a third reason:</div><div class=""><br class=""></div><div class="">3. `Decoder` doesn't guarantee there's a safety net if you use the wrong type. If you, say, decode an `Int32` using `Int64`, a decoder for some low-level binary type would be perfectly within its rights to read part of the next field, access everything subsequent to that point in a misaligned way, and go totally off the rails (as long as it doesn't violate memory safety).</div><div class=""><br class=""></div><div class="">That third reason is exactly the same as why `unsafeBitCast(_:to:)`, `bindMemory(to:capacity:)`, etc. all have a type-pinning parameter. Although Swift places no restrictions on return-type inference, in practice the core team thinks unconstrained return types are dangerous and should be used with care, only permitted when an API explicitly exists to ease conversions between different types. (`numericCast(_:)` is one example; I'm not sure if there are any others.) That's just their opinion, and of course you are always free to disagree with them, but I think it's a solid and easily justified one.</div></div></div></blockquote>Well put; this is basically what I was going to say.<br class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><div class="">Besides, if you really want this, it's easy to add with a pair of extensions:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>extension KeyedDecodingContainer {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>func decode&lt;T: Encodable&gt;(forKey key: Key) throws -&gt; T {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>return try decode(T.self, forKey: key)</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>extension UnkeyedDecodingContainer {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>func decode&lt;T: Encodable&gt;() throws -&gt; T {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                        </span>return try decode(T.self)</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=""><br class=""></div><div class="">(P.S. There might be a way to square this circle: If a CodingKey knew its type, the mere act of providing a CodingKey would be enough to pin the type. This would not only avoid both an explicit type-pinning parameter *and* unconstrained generic return types, it would also prevent you from accidentally specifying the wrong type during decoding. Rough example:</div><div class=""><br class=""></div><div class=""><span class="Apple-tab-span" style="white-space:pre">        </span>protocol CodingKey {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>associatedtype Value: Encodable</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>var stringValue: String { get }</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var intValue: Int? { get }</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(stringValue: String, intValue: Int?, as _: Value.Type)</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 CodingKey {</div><div class=""><span class="Apple-tab-span" style="white-space: pre;">                </span>var intValue: Int { return nil }</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>extension Person: Decodable {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                </span>struct CodingKeys&lt;Value&gt;: CodingKey {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>let stringValue: String</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(stringValue: String, intValue: Int? = nil, as _: Value.Type) {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                                </span>self.stringValue = stringValue</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>static let name = CodingKeys(stringValue: "name", as: String.self)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>static let age = CodingKeys(stringValue: "age", as: Int.self)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>static let pets = CodingKeys(stringValue: "pets", as: [Pet].self)</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>init(from decoder: Decoder) throws {</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>let c = try decoder.container(keyedBy: CodingKeys.self)</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>name = c.decode(.name)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>age = c.decode(.age)</div><div class=""><span class="Apple-tab-span" style="white-space:pre">                        </span>pets = c.decode(.pets)</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=""><br class=""></div><div class="">But this doesn't work for two reasons: You can't pass an entire generic type to `container(keyedBy:)` and you can't put constants in a generic type. You also lose the ability to construct a CodingKey from a String or Int, you lose the guarantee that all possible instances are known at compile time (I could imagine a linter checking that you've encoded/decoded all CodingKeys), and you lose all the convenient magic of enum raw types. You could address the "doesn't work" issues, but only by adding even more boilerplate. Still, if there's a way to do this that *doesn't* have so many disadvantages, we should seriously consider taking it.)</div></div></div></blockquote>FWIW, there’s another reason why a <font face="Menlo" class="">CodingKey</font>&nbsp;doesn’t know about the type you’ll be trying to decode with it: data migration.</div><div>Over time as your type changes, it’s perfectly reasonable to change the types of its properties (e.g. you realize that string identifiers are not needed somewhere in the app, and integer identifiers will do — better for efficiency). If some of those old types were written into archives, you’ll want to be able to still read them in new versions of your app, and potentially migrate them forward if possible. In that case, you wouldn’t want to have to keep an old key around just to represent the other type; you could just attempt to decode with a key and one type, and if it fails, try with the same key but a different type.<br class=""><br class=""><blockquote type="cite" class=""><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" 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=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>