> On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution > <[email protected]> wrote: > > I’m going to reply to this thread as a whole — apologies if there’s someone’s > comment that I’ve missed. > > 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. > 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, > > func foo() -> Int { return 42 } > func foo() -> Double { return .pi } > func consumesInt(_ x : Int) { print(x) } > > let x = foo() // Ambiguous use of foo() > consumesInt(x) // Even though x is going to be used as an Int > let y: Int = x // Same here > let x = foo() as Int 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 let x: Int = foo(). This has since been fixed, but it > was very confusing to try to figure out the unambiguous way to call it. > > Keep in mind that this isn’t an unreasonable thing to want to do: > > struct Foo { > var x: Int > init(from decoder: Decoder) throws { > let container = try decoder.container(keyedBy: CodingKeys.self) > > // Want to process an element before it’s assigned. > let x = container.decode(forKey: .x) // Ambiguous call > > // Or whatever. > if x < 0 { > self.x = x + 100 > else { > self.x = x * 200 > } > } > } > You can write let x: Int = container.decode(…) or let x = container.decode(…) > as Int, but this isn’t always intuitive. > That’s where I disagree. Let me try to prove my point:
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 container.encode(x as Double, forKey: .x). Wouldn’t that be an argument to have an API like this: func encode<T>(_ value: Data?, forKey key: Key, as type: T.Type) throws 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: let cgFloat: CGFloat = 42 let pi = 3.14159265359 as Float let person = factory.get<Person>() // potential feature in Generics Manifesto 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. > Consider also that the metatype would also be necessary for decode<Value : > Codable>(_ type: Value.Type, forKey: Key) -> Value because the return value > of that certainly could be ambiguous in many cases. > > Finally, the metatype arg allows you to express the following succinctly: let > v: SuperClass = container.decode(SubClass.self, forKey: .v). > > In the general case (decode<Value : Codable>) 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?" > > Matthew offered func decode<T>(_ key: Key, as type: T.Type = T.self) throws > -> T which looks appealing, but: > > Doesn’t help resolve the ambiguity either > Allows for 3 ways of expressing the same thing (let x: Int = decode(key), let > x = decode(key) as Int, and let x = decode(key, as: Int.self)) > The cognitive overhead of figuring out all of the ambiguity goes away when > we’re consistent everywhere. > FWIW, too, I am not convinced that Foundation should add API just because 3rd > parties will add it. > 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. > 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. > > On 16 Mar 2017, at 11:46, Matthew Johnson via swift-evolution wrote: > > > >> On Mar 16, 2017, at 1:34 PM, Zach Waldowski via swift-evolution >> <[email protected] <mailto:[email protected]>> wrote: >> >> On Thu, Mar 16, 2017, at 02:23 PM, Matthew Johnson via swift-evolution wrote: >>> 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: >>> >>> let i = decode(.myKey) as Int >> >> 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. >> >> Any official Swift or Foundation API shouldn't, or shouldn't need to, make >> use of "tricky" syntax. > > 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. > >> >>> If we don’t support this in Foundation we will continue to see 3rd party >>> libraries that do this. >> >> 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? > > 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. > > 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. > >> >> Zach Waldowski >> [email protected] <mailto:[email protected]> >> >> >> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution > > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
