> 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

Reply via email to