> On Sep 24, 2016, at 7:31 PM, Dany St-Amant <[email protected]> wrote:
> 
> Reading some old threads...
> 
> Le 16 août 2016 à 15:12, Xiaodi Wu via swift-evolution 
> <[email protected] <mailto:[email protected]>> a écrit :
> 
>> On Tue, Aug 16, 2016 at 12:14 PM, Justin Jia <[email protected] 
>> <mailto:[email protected]>> wrote:
>> I was trying to argue with reason. You kept stating your *opinion*. You 
>> still didn't explain *why*. For example, why "if statements can and function 
>> calls can't" and why "this severely violates user expectations"?
>> 
>> These were not meant as expressions of opinion. Currently, in Swift, `if` 
>> statements can short circuit and function calls cannot. Your proposal would 
>> introduce short-circuiting where currently there can be none, and thus it 
>> would severely violate user expectations.
> 
> Function calls can currently be short-circuited... if there's try and throw 
> involved.
> 
> let z = try g(f1(a), f2(b), f3(c)) // Must be within do {} catch {}
> 
> Assuming f1(), f2(), f3() can all throws, f2() is only called if f1() did not 
> throw, and f3() if neither f1() nor f2() threw. The behavior is/seems to be: 
> Pure left to right execution order regardless of throwing ability.
> 
> If g() doesn't throw, the above (with exact same behavior) can be written 
> more verbosely and explicitly as:
> 
> let y = g(try f1(a), try f2(b), try f3(c)) // Must be within do {} catch {}
> 
> Yet another way to do the call is:
> 
> let x = try? g(f1(a), f2(b), f3(c)) // z is nil on throws
> 
> So implementing something like what Justin is asking should fit within Swift, 
> as long as it follows the try short-circuit logic. However, the use of a 
> trailing question-mark to provide this functionality is not explicit enough 
> to my taste (and to my weakening eyesight). Could we reuse let but with a 
> question-mark? Or maybe guard.
> 

Good point! Edge cases always exist.

> let z = g(let? f1(a), let? f2(b), let? f3(c))
> // z is nil on fX() == nil, otherwise Optional(g()) just like try? wrapping
> // left to right short-circuit à la let z = try?
> 

This sounds like a good idea. Moving the keyword to the front is more explicit. 
But `let? f1(a)` seems a little bit weird to me.

What about `let x = if? foo(x, y)` But… should we introduce `if!` as well?

```
func foo(x: Any, y: Any) { … }

let x: Any? = nil
let y: Any? = nil
if? foo(x, y) // If x and y both can be unwrapped, execute foo().
if? foo(x?, y?) // Or if we want to be a little bit more clear, specify which 
argument could be optional
```

```
if! foo(x, y) // Will crash if nil is found.
if! foo(x!, y!) // To be more clear
```

Backward compatibility:

```
foo(x!, y!) // warning: add if! before the function
```

> Though, this may ask for also supporting something like:
> 
> let x = g(let? try? f1(a), let? try? f2(b), let? try? f3(c))
> 
> This allow selective discard of throws, instead of a discard all of a plain 
> 'let x = try? ...'
> 

Yes.

> Dany
> 
>> ... snip ...
>>>> 
>>>>>> On Aug 16, 2016, at 1:16 AM, Xiaodi Wu <[email protected] 
>>>>>> <mailto:[email protected]>> wrote:
>>>>>> 
>>>>>> On Mon, Aug 15, 2016 at 12:07 PM, Xiaodi Wu <[email protected] 
>>>>>> <mailto:[email protected]>> wrote:
>>>>>> On Mon, Aug 15, 2016 at 11:43 AM, Justin Jia 
>>>>>> <[email protected] <mailto:[email protected]>> 
>>>>>> wrote:
>>>>>> I believe the core team has considered 99% of the ideas in the mailing 
>>>>>> list in the past, but it doesn’t mean we can’t discuss it, right?
>>>>>> .. snip ...
>>>>>> 
>>>>>> Back to the original topic.
>>>>>> 
>>>>>> I spent some time thinking and changed my mind again. I think solution 1 
>>>>>> is most reasonable. It is consistent with if statements. Instead of 
>>>>>> treating it as sugar for `if let`, we can treat it as sugar for `guard`, 
>>>>>> which is much easy to understand and remember.
>>>>>> 
>>>>>> -
>>>>>> 
>>>>>> Below is the reason why I think this feature is important (quoted from 
>>>>>> another email).
>>>>>> 
>>>>>> The problem with `if let` is you need to call the function inside { }.
>>>>>> 
>>>>>> ```
>>>>>> /* code 1 */
>>>>>> if let x = x, let y = y {
>>>>>>     /* code 2, depends on x and y to be non-optional */
>>>>>>     let z = foo(x, y)
>>>>>>     if let z = z {
>>>>>>         bar(z)
>>>>>>     }
>>>>>>     /* code 3, depends on x and y to be non-optional */
>>>>>> }
>>>>>> /* code 4 */
>>>>>> ```
>>>>>> 
>>>>>> I can't use `guard` for this situation because guard will force me to 
>>>>>> leave the entire function.
>>>>>> 
>>>>>> ```
>>>>>> /* code 1 */
>>>>>> guard let x = x, y = y else { return }
>>>>>> /* code 2, depends on x and y to be non-optional */
>>>>>> guard let z = foo(x, y) else { return }
>>>>>> bar(z)
>>>>>> /* code 3, depends on x and y to be non-optional */ <- This won't 
>>>>>> execute if z is nil
>>>>>> /* code 4 */ <- This won't execute if x, y or z is nil
>>>>>> ```
>>>>>> 
>>>>>> Then surround it with a do block.
>>>>>> 
>>>>>> ```
>>>>>> out: do {
>>>>>>   guard foo else { break out }
>>>>>>   guard bar else { break out }
>>>>>>   /* other code */
>>>>>> }
>>>>>> ```
>>>>>> 
>>>>>> Or, more idiomatically, since your use case is that you want /* code 4 
>>>>>> */ to be executed no matter what, while everything else depends on x and 
>>>>>> y not being nil:
>>>>>> 
>>>>>> ```
>>>>>> defer { /* code 4 */ }
>>>>>> guard let x = x, let y = y else { return }
>>>>>> /* code 2 */
>>>>>> /* code 3 */
>>>>>> ```
>>>>>> 
>>>>>> 
>>>>>> What I really want is some like this:
>>>>>> 
>>>>>> ```
>>>>>> / * code 1 */
>>>>>> let z = foo(x?, y?)
>>>>>> /* code 2, depends on x and y to be non-optional, use x? and y? */
>>>>>> bar(z?)
>>>>>> /* code 3, depends on x and y to be non-optional, use x? and y? */
>>>>>> /* code 4 */
>>>>>> ```
>>>>>> This is much easier to read. Sometimes people choose to use `guard` to 
>>>>>> avoid `{ }`, which usually lead to code could easily get wrong (like the 
>>>>>> second example).
>>>>>> 
>>>>>> Sincerely,
>>>>>> Justin
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>> 
>>>>>>> On Aug 15, 2016, at 11:41 PM, Xiaodi Wu <[email protected] 
>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>> 
>>>>>>> What do you mean, limited to variables? What about a computed property? 
>>>>>>> You will have the same problem.
>>>>>>> 
>>>>>>> I'm not sure where you want to go with this, given that the core team 
>>>>>>> has considered the same idea in the past and found these issues to have 
>>>>>>> no good solution.
>>>>>>> 
>>>>>>> On Mon, Aug 15, 2016 at 04:56 Justin Jia 
>>>>>>> <[email protected] 
>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>> IMO I don't this bar should be evaluated unless we decide if let can 
>>>>>>> accept non-optional values. 
>>>>>>> 
>>>>>>> Actually, what if we allow if let to accept non-optional values?
>>>>>>> 
>>>>>>> I agree this is confusing at the beginning. But people who are not 
>>>>>>> familiar with the detail design can avoid this situation easily. People 
>>>>>>> who are familiar with the design can adopt it quickly. Sometimes, this 
>>>>>>> is unavoidable. 
>>>>>>> 
>>>>>>> Btw, do you think this is still something nice to have if we limit this 
>>>>>>> syntax to only variables?
>>>>>>> 
>>>>>>> On Aug 15, 2016, at 4:59 PM, Xiaodi Wu <[email protected] 
>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>> 
>>>>>>>> On Mon, Aug 15, 2016 at 3:55 AM, Xiaodi Wu <[email protected] 
>>>>>>>> <mailto:[email protected]>> wrote:
>>>>>>>> On Mon, Aug 15, 2016 at 3:25 AM, Justin Jia via swift-evolution 
>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>> 
>>>>>>>>> On Aug 15, 2016, at 4:09 PM, Charlie Monroe 
>>>>>>>>> <[email protected] <mailto:[email protected]>> wrote:
>>>>>>>>> 
>>>>>>>>> The example above was to better demonstrate the problem with *when* 
>>>>>>>>> to evaluate the latter argument. Why should both arguments be 
>>>>>>>>> evaluated *before* the if statement? If both calls return Optionals, 
>>>>>>>>> 
>>>>>>>>> if let x = bar(42), y = baz(42) { ... }
>>>>>>>>> 
>>>>>>>>> is how would I write it without the suggested syntax - baz(42) will 
>>>>>>>>> *not* be evaluated if bar(42) returns nil. Which bears a question why 
>>>>>>>>> would 
>>>>>>>>> 
>>>>>>>>> foo(bar(42)?, baz(42)?) 
>>>>>>>>> 
>>>>>>>>> evaluate both arguments even if the first one is nil, making it 
>>>>>>>>> incosistent with the rest of the language?
>>>>>>>> 
>>>>>>>> I see your point. I understand that maybe 1/2 of the people think we 
>>>>>>>> should evaluate both arguments and 1/2 of the people think we should 
>>>>>>>> only evaluate the first argument.
>>>>>>>> 
>>>>>>>> I changed my idea a little bit. Now I think you are right. We should 
>>>>>>>> only evaluate the first argument in your example. It’s not only 
>>>>>>>> because of inconsistent, but also because the language should at least 
>>>>>>>> provide a way to “short-circuit” to rest of the arguments.
>>>>>>>> 
>>>>>>>> If they want to opt-out this behavior, they can always write:
>>>>>>>> 
>>>>>>>> ```
>>>>>>>> let x = bar(42)
>>>>>>>> let y = baz(42)
>>>>>>>> foo(x?, y?)
>>>>>>>> ```
>>>>>>>> 
>>>>>>>> Well, that was just the easy part. Now, suppose bar is the function 
>>>>>>>> that isn't optional.
>>>>>>>> 
>>>>>>>> ```
>>>>>>>> foo(bar(42), baz(42)?)
>>>>>>>> ```
>>>>>>>> 
>>>>>>>> Is bar evaluated if baz returns nil? If you want this syntax to be 
>>>>>>>> sugar for if let, then the answer is yes.
>>>>>>>> 
>>>>>>>> s/yes/no/
>>>>>>>>  
>>>>>>>> If short-circuiting works left-to-right, then the answer is no.
>>>>>>>> 
>>>>>>>> s/no/yes/ 
>>>>>>>> 
>>>>>>>> (See? Confusing.)
>>>>>>>>  
>>>>>>>> This is very confusing, and there is no good intuitive answer. 
>>>>>>>> 
>>>>>>>> 
>>>>>>>> _______________________________________________
>>>>>>>> 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