<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=""><br class=""><div><blockquote type="cite" class=""><div class="">On Mar 16, 2017, at 3:27 PM, David Hart <<a href="mailto:david@hartbit.com" class="">david@hartbit.com</a>> 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=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
<meta http-equiv="Content-Type" content="text/xhtml; charset=utf-8" class="">
<div class="">
<div style="font-family:sans-serif" class=""><div style="white-space:normal" class=""><p dir="auto" class="">I’m going to reply to this thread as a whole — apologies if there’s someone’s comment that I’ve missed.</p><p dir="auto" class="">This is something that has come up in internal review, and we’ve certainly given it thought. As Zach has already mentioned, the primary concern with overloading based on return type is ambiguity.<br class="">
There are many cases in which Swift’s type system currently does not handle ambiguity in the way that you would expect, and it can be very surprising. For instance,</p>
<pre style="background-color: rgb(247, 247, 247); border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; margin-left: 15px; margin-right: 15px; max-width: 90vw; overflow-x: auto; padding: 5px;" bgcolor="#F7F7F7" class=""><code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0" bgcolor="#F7F7F7" class=""><span style="color: #008800; font-weight: bold" class="">func</span> <span style="color: #0066BB; font-weight: bold" class="">foo</span>() -> <span style="color: #007020" class="">Int</span> { <span style="color: #008800; font-weight: bold" class="">return</span> <span style="color: #0000DD; font-weight: bold" class="">42</span> }
<span style="color: #008800; font-weight: bold" class="">func</span> <span style="color: #0066BB; font-weight: bold" class="">foo</span>() -> <span style="color: #007020" class="">Double</span> { <span style="color: #008800; font-weight: bold" class="">return</span> .pi }
<span style="color: #008800; font-weight: bold" class="">func</span> <span style="color: #0066BB; font-weight: bold" class="">consumesInt</span>(<span style="color: #008800; font-weight: bold" class="">_</span> x : <span style="color: #007020" class="">Int</span>) { <span style="color: #007020" class="">print</span>(x) }
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">x</span> = foo() <span style="color: #888888" class="">// Ambiguous use of foo()</span>
consumesInt(x) <span style="color: #888888" class="">// Even though x is going to be used as an Int</span>
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">y</span>: <span style="color: #007020" class="">Int</span> = x <span style="color: #888888" class="">// Same here</span>
</code></pre><p dir="auto" class=""><code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x = foo() as Int</code> works now, but it actually didn’t always — until a somewhat recent version of Swift AFAICT, the only way to resolve the ambiguity was through <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x: Int = foo()</code>. This has since been fixed, but it was very confusing to try to figure out the unambiguous way to call it.</p><p dir="auto" class="">Keep in mind that this isn’t an unreasonable thing to want to do:</p>
<pre style="background-color: rgb(247, 247, 247); border-top-left-radius: 5px; border-top-right-radius: 5px; border-bottom-right-radius: 5px; border-bottom-left-radius: 5px; margin-left: 15px; margin-right: 15px; max-width: 90vw; overflow-x: auto; padding: 5px;" bgcolor="#F7F7F7" class=""><code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0" bgcolor="#F7F7F7" class=""><span style="color: #008800; font-weight: bold" class="">struct</span> <span style="color: #BB0066; font-weight: bold" class="">Foo</span> {
<span style="color: #008800; font-weight: bold" class="">var</span> <span style="color: #996633" class="">x</span>: <span style="color: #007020" class="">Int</span>
<span style="color: #008800; font-weight: bold" class="">init</span>(from decoder: Decoder) throws {
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">container</span> = try decoder.container(keyedBy: CodingKeys.<span style="color: #008800; font-weight: bold" class="">self</span>)
<span style="color: #888888" class="">// Want to process an element before it’s assigned.</span>
<span style="color: #008800; font-weight: bold" class="">let</span> <span style="color: #996633" class="">x</span> = container.decode(forKey: .x) <span style="color: #888888" class="">// Ambiguous call</span>
<span style="color: #888888" class="">// Or whatever.</span>
<span style="color: #008800; font-weight: bold" class="">if</span> x <span style="color: #333333" class=""><</span> <span style="color: #0000DD; font-weight: bold" class="">0</span> {
<span style="color: #008800; font-weight: bold" class="">self</span>.x = x <span style="color: #333333" class="">+</span> <span style="color: #0000DD; font-weight: bold" class="">100</span>
<span style="color: #008800; font-weight: bold" class="">else</span> {
<span style="color: #008800; font-weight: bold" class="">self</span>.x = x <span style="color: #333333" class="">*</span> <span style="color: #0000DD; font-weight: bold" class="">200</span>
}
}
}
</code></pre><p dir="auto" class="">You can write <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x: Int = container.decode(…)</code> or <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x = container.decode(…) as Int</code>, but this isn’t always intuitive.<br class=""></p></div></div></div></div></blockquote><div class="">That’s where I disagree. Let me try to prove my point:</div><div class=""><br class=""></div><div class="">You bring up the example of having to store the decoded value in a variable before setting it to a typed property. But its also not unreasonable to want to do the same thing when encoding the value, possibly storing it into a different type. If we follow that argument, its also not very intuitive to have to do</div><div class=""><font face="Menlo" class=""><br class=""></font></div><div class=""><font face="Menlo" class="">container.encode(x as Double, forKey: .x)</font>.</div><div class=""><br class=""></div><div class="">Wouldn’t that be an argument to have an API like this:</div><div class=""><br class=""></div><div class=""><font face="Menlo" class="">func encode<T>(_ value: Data?, forKey key: Key, as type: T.Type) throws</font></div><div class=""><br class=""></div><div class="">I would argue that type inference is a core feature in Swift and that we should embrace it. I believe that in most cases the return value of encode will be stored into a typed property and type inference will do the right thing. In the few cases where the type has to be enforced, the patterns you mention above are not weird syntax; they are used and useful all over Swift:</div><div class=""><br class=""></div><div class="">let cgFloat: CGFloat = 42</div><div class="">let pi = 3.14159265359 as Float</div><div class="">let person = factory.get<Person>() // potential feature in Generics Manifesto</div><div class=""><br class=""></div><div class="">The way I think about it is that the type argument is already there as a generic parameter. Adding an extra argument that needs to be explicitly given on every single call feels like unneeded verbosity to me.</div></div></div></div></blockquote><div><br class=""></div><div>I agree with everything David says here.</div><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=""><blockquote type="cite" class=""><div class=""><div class=""><div style="font-family:sans-serif" class=""><div style="white-space:normal" class=""><p dir="auto" class="">
Consider also that the metatype would also be necessary for <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">decode<Value : Codable>(_ type: Value.Type, forKey: Key) -> Value</code> because the return value of that certainly could be ambiguous in many cases.</p><p dir="auto" class="">Finally, the metatype arg allows you to express the following succinctly: <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let v: SuperClass = container.decode(SubClass.self, forKey: .v)</code>.</p><p dir="auto" class="">In the general case (<code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">decode<Value : Codable></code>) we would need the metatype to avoid ambiguity. It’s not strictly necessary for primitive types, but helps in the case of ambiguity, and solves the conceptual overhead of "Why do I specify the type sometimes but not others? Why are some of these types special? Should I always provide the type? Why wouldn’t I?"</p><p dir="auto" class="">Matthew offered <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">func decode<T>(_ key: Key, as type: T.Type = T.self) throws -> T</code> which looks appealing, but:</p>
<ol class="">
<li value="1" class="">Doesn’t help resolve the ambiguity either</li>
<li value="2" class="">Allows for 3 ways of expressing the same thing (<code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x: Int = decode(key)</code>, <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x = decode(key) as Int</code>, and <code style="background-color:#F7F7F7; border-radius:3px; margin:0; padding:0 0.4em" bgcolor="#F7F7F7" class="">let x = decode(key, as: Int.self)</code>)</li>
</ol><p dir="auto" class="">The cognitive overhead of figuring out all of the ambiguity goes away when we’re consistent everywhere.<br class="">
FWIW, too, I am not convinced that Foundation should add API just because 3rd parties will add it.</p></div></div></div></div></blockquote><div class="">Agreed. Foundation should not add API just because 3rd parties do it. But 3rd parties should not be dismissed entirely nonetheless. They are a good breeding ground for ideas to spawn and shape Swift in interesting ways.</div></div></div></div></blockquote><div><br class=""></div><div>+1. The point is not that we should do everything 3rd parties do. But we should also not leave a gap in Foundation where the community has identified a lighter syntactic approach that has been used successfully in practice. This just results in a bunch of different implementations of the same thing (probably with small incompatibilities). </div><div><br class=""></div><div>If wrappers are common enough the need for everyone to write them is a disservice to the community. It’s hard to say if that will happen in this case but I suspect it might. I know writing one is the first thing I would do if this proposal is accepted as-is and I suspect many other people would feel the same way.</div><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=""><blockquote type="cite" class=""><div class=""><div class=""><div style="font-family:sans-serif" class=""><div style="white-space:normal" class=""><p dir="auto" class="">The ambiguity in the general case cannot be solved by wrappers, and I would prefer to provide one simple, consistent solution; if 3rd parties would like to add wrappers for their own sake, then I certainly encourage that.</p><p dir="auto" class="">On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote:</p><div class=""><br class="webkit-block-placeholder"></div></div>
<div style="white-space:normal" class=""></div>
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class=""><div id="42F7084E-4D77-4CB6-A834-C0F0E70F1875" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">
<title class=""></title>
<div class=""><div style="font-family:Arial;" class="">On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote:<br class=""></div>
<blockquote type="cite" class=""><div style="font-family:Arial;" class="">I don’t have an example but I don’t see a problem either. There are two options for specifying the return type manually. We can use the signature you used above and use `as` to specify the expected type:<br class=""></div>
<div class=""><div class=""><br class=""></div>
<div class="">let i = decode(.myKey) as Int<br class=""></div>
</div>
</blockquote><div style="font-family:Arial;" class=""><br class=""></div>
<div style="font-family:Arial;" class="">The awkwardness of this syntax is exactly what I'm referring to. Would a beginner know to use "as Int" or ": Int"? Why would they? The "prettiness" of the simple case doesn't make up for how difficult it is to understand and fix its failure cases.<br class=""></div>
<div style="font-family:Arial;" class=""><br class=""></div>
<div style="font-family:Arial;" class="">Any official Swift or Foundation API shouldn't, or shouldn't need to, make use of "tricky" syntax.<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">I don’t think this is especially tricky. Nevertheless, we can avoid requiring this syntax by moving the type argument to the end and providing a default. But I think return type inference is worth supporting. It has become widely adopted by the community already in this use case.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">
<div style="font-family:Arial;" class=""><br class=""></div>
<blockquote type="cite" class=""><div class=""><div class="">If we don’t support this in Foundation we will continue to see 3rd party libraries that do this.<br class=""></div>
</div>
</blockquote><div style="font-family:Arial;" class=""><br class=""></div>
<div style="font-family:Arial;" class="">The proposal's been out for less than 24 hours, is it really productive to already be taking our ball and go home over such a minor thing?<br class=""></div></div></div></blockquote><div class=""><br class=""></div><div class="">I don’t think that’s what I’m doing at all. This is a fantastic proposal. I’m still working through it and writing up my more detailed thoughts.</div><div class=""><br class=""></div><div class="">That said, as with many (most?) first drafts, there is room for improvement. I think it’s worth pointing out the syntax that many of us would like to use for decoding and at least considering including it in the proposal. If the answer is that it’s trivial for those who want to use subscripts to write the wrappers for return type inference and / or subscripts themselves that’s ok. But it’s a fair topic for discussion and should at least be addressed as an alternative that was rejected for a specific reason.</div><br class=""><blockquote type="cite" class=""><div class=""><div class="">
<div style="font-family:Arial;" class=""><div style="font-family:Arial;" class=""><div style="font-family:Arial;" class=""><br class=""></div>
</div>
<div style="font-family:Arial;" class=""><div style="font-family:Arial;" class=""><span class="font" style="font-family:arial, sans-serif, sans-serif">Zach Waldowski</span><br class=""></div>
</div>
<div id="sig40804545" class=""><div class="signature"><a href="mailto:zach@waldowski.me" class=""><span class="font" style="font-family:arial, sans-serif, sans-serif">zach@waldowski.me</span></a><br class=""></div>
</div>
<div class=""><div style="font-family:Arial;" class=""><br class=""></div>
</div>
<div class=""><div style="font-family:Arial;" class=""><br class=""></div>
</div>
<div class=""><div style="font-family:Arial;" class=""><br class=""></div>
</div>
</div>
<div style="font-family:Arial;" class=""><br class=""></div>
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></blockquote>
<div style="white-space:normal" class="">
<blockquote style="border-left:2px solid #777; color:#777; margin:0 0 5px; padding-left:5px" class="">
</blockquote><p dir="auto" class="">_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" style="color:#3983C4" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></p>
</div>
<div style="white-space:normal" class="">
</div>
</div>
</div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></blockquote></div><br class=""></body></html>