> On Aug 18, 2016, at 10:11 AM, Xiaodi Wu <[email protected]> wrote:
> On Thu, Aug 18, 2016 at 11:30 AM, John McCall <[email protected] 
> <mailto:[email protected]>> wrote:
>> On Aug 18, 2016, at 8:46 AM, Xiaodi Wu <[email protected] 
>> <mailto:[email protected]>> wrote:
>> The issue would be that, in the case of "try? foo()", nil and .some(nil) 
>> might mean very different things.
> 
> This is true of a?.foo() as well.  But yes, I think it is more likely that 
> someone would want to treat them differently for try?.
> 
> Agreed.
> 
> My proposed solution was half-baked, but it may be workable--I'm not 
> suggesting typing decisions based on a dynamic property, of course. It'd be 
> something like this:
> 
> `as?` would produce a result of a type named something like 
> CastingOptional<T>, which on assignment or essentially any other operation is 
> promoted/bridged/[insert much more correct term here] to an Optional<T> like 
> how T is automatically promoted to Optional<T>. However, `try?` will not wrap 
> a CastingOptional<T> into an Optional<Optional<T>>.

The way this is done for ?-chaining is that the result of the chain is coerced 
to T?, for a fresh unbound type T.  If the result is already of type U?, T will 
be bound to U and there's no "stacking" of optionals; if the result is a 
non-optional type V, T will be bound to V and therefore the chain gains a level 
of optionality.  I think that is simpler and more consistent than inventing a 
new flavor of Optional with complex conversion and defaulting rules.

John.

>  
> John.
> 
>> On Thu, Aug 18, 2016 at 10:40 John McCall <[email protected] 
>> <mailto:[email protected]>> wrote:
>>> On Aug 18, 2016, at 8:19 AM, Xiaodi Wu via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>> Lots of interesting points here. I do think there's an improvement possible 
>>> here, but it's actually along the lines of Sam's original suggestion #3 
>>> (not vis-a-vis all of Swift, but specifically for how try? composes with 
>>> as?):
>>> 
>>> A. I'm in favor of the current behavior where try prefixes an entire 
>>> statement: it solves the precise issue of multiple nested optionals or 
>>> multiple unwrapping of optionals in the situation where one statement has 
>>> calls to many throwing functions. It says instead, I want nil if anything 
>>> in this statement throws, otherwise, give me .some(value).
>>> 
>>> Sam--I think you may have misunderstood Charles's explanation. He's not 
>>> saying "try?" attaches with lower or higher precedence as compared to 
>>> "as?". Rather, I think the mental model is that "try?" prefixes the whole 
>>> right-hand side (rhs), and if *any* call on the rhs throws, the whole rhs 
>>> evaluates to nil, but if *any* call could potentially throw but doesn't, 
>>> "try?" wraps the entire rhs and gives you .some(value). IMO, this is pretty 
>>> sensible for the reason he gives.
>>> 
>>> B. I'm in favor of warning instead of error, for precisely the internal 
>>> discussion rationale communicated by Slava. I'm willing to live with "try? 
>>> 42" being only a warning if that means my code won't stop compiling when 
>>> someone decides a library function doesn't need to throw.
>>> 
>>> Sam--here, changing warning to error would not solve your original problem, 
>>> because in that example "try?" does prefix at least one throwing function, 
>>> so you wouldn't get an error anyway.
>>> 
>>> C. However, given the thinking in (A), I do think how "try?" composes with 
>>> "as?" is a little counterintuitive or at least overly ceremonious, though 
>>> technically it is possible to reason through.
>>> 
>>> It's true that currently you can use the multiple nested optionals to 
>>> figure out whether either a throwing function threw (but not which throwing 
>>> function out of potentially more than one) or whether the cast did not 
>>> succeed. But, since "try?" after all means "give me nil if anything 
>>> throws," it kind of makes less sense that you get all this nesting and 
>>> detailed information when it composes with "as?". If you really wanted that 
>>> level of detail, you could always evaluate "try?" and "as?" in separate 
>>> statements. What I'd propose instead is this:
>>> 
>>> If "try?" is composed with "as?", and "as?" yields "nil", then "try?" 
>>> should not wrap that value in another optional.
>> 
>> We can't make the typing decision dependent on a dynamic property like 
>> whether the cast fails.  And I don't like the idea of changing its typing 
>> rule based on the form of the nested expression.  But we could make "try? 
>> foo()" avoid adding an extra level of optionality, the same way that 
>> "a?.foo()" does.
>> 
>> John.
>> 
>>> 
>>> Does that sound sensible?
>>> 
>>> 
>>> On Thu, Aug 18, 2016 at 3:54 AM, Sikhapol Saijit via swift-evolution 
>>> <[email protected] <mailto:[email protected]>> wrote:
>>> 
>>>> On Aug 18, 2016, at 3:42 PM, Slava Pestov <[email protected] 
>>>> <mailto:[email protected]>> wrote:
>>>> 
>>>>> 
>>>>> On Aug 18, 2016, at 12:52 AM, David Hart via swift-evolution 
>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>> 
>>>>> Opinions inline:
>>>>> 
>>>>>> On 18 Aug 2016, at 07:43, Sikhapol Saijit via swift-evolution 
>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>> 
>>>>>> Hi all,
>>>>>> 
>>>>>> 
>>>>>> Yesterday I tried this code:
>>>>>> 
>>>>>> func couldFailButWillNot() throws -> Any {
>>>>>>     return 42
>>>>>> }
>>>>>> 
>>>>>> if let a = try? couldFailButWillNot() as? Int {
>>>>>>     print(a)
>>>>>> }
>>>>>> 
>>>>>> And was surprised that the output was Optional(42) on both Swift 2 and 
>>>>>> Swift 3.
>>>>>> I always have the impression that when a variable is resolved with if 
>>>>>> let it will never be optional.
>>>>>> 
>>>>>> So, with a little investigation, I found out that it happens because as? 
>>>>>> has higher precedence than try? and is evaluated first.
>>>>>> And the whole expression `try? couldFailButWillNot() as? Int` evaluated 
>>>>>> as Optional(Optional(42)).
>>>>>> 
>>>>>> Also, I’m surprised that try? can be used with non-method-call.
>>>>>> This code: `print(try? 42)` will print Optional(42).
>>>>>> 
>>>>>> So, the questions are:
>>>>>> 
>>>>>> 1. Is it intentional that try? can be used with a "non-method-call" and 
>>>>>> return an optional of the type that follows?
>>>>> 
>>>>> I think this is the real solution. try and try? should not be allowed on 
>>>>> non-throwing functions or expressions.
>>>> 
>>>> This is a warning right now — do you think it should be an error?
>>>> 
>>>> Slavas-MacBook-Pro:~ slava$ cat ttt.swift 
>>>> func f() {}
>>>> 
>>>> func g() {
>>>>   try f()
>>>>   try? f()
>>>> }
>>>> 
>>>> Slavas-MacBook-Pro:~ slava$ swiftc ttt.swift 
>>>> ttt.swift:4:3: warning: no calls to throwing functions occur within 'try' 
>>>> expression
>>>>   try f()
>>>>   ^
>>>> ttt.swift:5:8: warning: no calls to throwing functions occur within 'try' 
>>>> expression
>>>>   try? f()
>>>>        ^
>>> 
>>> Thank you Slava,
>>> 
>>> While I think using try/try? on anything but a throwing function call 
>>> should be an error, right now it even works with anything. `try? 42` will 
>>> just wrap 42 in an optional and give some warning now.
>>> 
>>>> 
>>>>> 
>>>>>> 2. Should we design try? to have higher precedence than as? or any 
>>>>>> operators at all?
>>>>>> My intuition tells me that 
>>>>>> let a = try? couldFailButWillNot() as? Int
>>>>>> should be equivalent to
>>>>>> let a = (try? couldFailButWillNot()) as? Int 
>>>>> 
>>>>> That’s worth considering. try feels like it should tie very strongly with 
>>>>> the throwing expression.
>>>>> 
>>>>>> 3. Do you think that doubly-nested optional (or multi-level-nested 
>>>>>> optional) is confusing and should be removed from Swift? (Yes, I’ve seen 
>>>>>> this blog post Optionals Case Study: valuesForKeys 
>>>>>> <https://developer.apple.com/swift/blog/?id=12>).
>>>>>> For me Optional(nil) (aka Optional.Some(Optional.None))) doesn’t make 
>>>>>> much sense. 
>>>>>> Maybe, one of the solution is to always have optional of optional merged 
>>>>>> into a single level optional? Like Optional(Optional(Optional(42))) 
>>>>>> should be the merged to and evaluated as Optional(42).
>>>>> 
>>>>> I don’t think this is the solution. Even if it was, how would you expect 
>>>>> to “remove” them from Swift? Optionals are simply an enum with an 
>>>>> associated value. We’d have to introduce a language feature to restrict 
>>>>> values that can be stored in enum cases? It sounds awfully complicated.
>>>>> 
>>>>>> BTW, the code above is merely for a demonstration. The actual code was 
>>>>>> more of something like this:
>>>>>> 
>>>>>> func parse(JSON: Data) throws -> Any {
>>>>>>     // …
>>>>>> }
>>>>>> 
>>>>>> if let dict = try? parse(JSON: json) as? [String: Any] {
>>>>>>     // assume dict is a valid [String: Any] dictionary
>>>>>>     // …
>>>>>> }
>>>>>> 
>>>>>> I’m new to this mailing list so I’m not sure if this belongs here. I’m 
>>>>>> sorry in advance if it doesn’t.
>>>>>> 
>>>>>> 
>>>>>> Thank you,
>>>>>> Sam
>>>>>> _______________________________________________
>>>>>> 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 
>>> <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]
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to