> On Mar 16, 2017, at 3:27 PM, David Hart <[email protected]> wrote: > > >> On 16 Mar 2017, at 20:55, Itai Ferber via swift-evolution >> <[email protected] <mailto:[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.
I agree with everything David says here. >> 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. +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). 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. >> 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 >>> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> >> _______________________________________________ >> swift-evolution mailing list >> [email protected] <mailto:[email protected]> >> https://lists.swift.org/mailman/listinfo/swift-evolution >> <https://lists.swift.org/mailman/listinfo/swift-evolution> >> _______________________________________________ >> 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
