Oops, completely missed about 57 messages in the meat of this discussion, so apologies if what I said was already suggested.
On Sun, Sep 25, 2016 at 4:35 AM Dennis Lysenko <dennis.s.lyse...@gmail.com> wrote: > Could take a page out of Kotlin's book: > > x.let { foo(it) } // default argument name that isn't $0 > > IMO, this syntax looks better as a one liner than "if x? { foo(x) }". > > The edge case here, with foo and bar being optional-returning functions, > becomes: > (foo(42), bar(43)).let { x, y in foo(x, y) } // default argument "it" here > is a tuple so you can't pass it directly to the function, therefore you > have to name x and y explicitly > > In which case it should be abundantly clear to the reader that there is NO > short-circuiting and both foo and bar are evaluated as a tuple before the > "let" function is called on that tuple. > > On Sun, Sep 25, 2016 at 3:24 AM Justin Jia via swift-evolution < > swift-evolution@swift.org> wrote: > >> On Sep 24, 2016, at 7:31 PM, Dany St-Amant <dsa....@icloud.com> wrote: >> >> Reading some old threads... >> >> Le 16 août 2016 à 15:12, Xiaodi Wu via swift-evolution < >> swift-evolution@swift.org> a écrit : >> >> On Tue, Aug 16, 2016 at 12:14 PM, Justin Jia < >> justin.jia.develo...@gmail.com> 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 <xiaodi...@gmail.com> wrote: >>>>>> >>>>>> On Mon, Aug 15, 2016 at 12:07 PM, Xiaodi Wu <xiaodi...@gmail.com> >>>>>> wrote: >>>>>> >>>>>>> On Mon, Aug 15, 2016 at 11:43 AM, Justin Jia < >>>>>>> justin.jia.develo...@gmail.com> 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 <xiaodi...@gmail.com> >>>>>>>> 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 < >>>>>>>> justin.jia.develo...@gmail.com> 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 <xiaodi...@gmail.com> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>> On Mon, Aug 15, 2016 at 3:55 AM, Xiaodi Wu <xiaodi...@gmail.com> >>>>>>>>> wrote: >>>>>>>>> >>>>>>>>>> On Mon, Aug 15, 2016 at 3:25 AM, Justin Jia via swift-evolution < >>>>>>>>>> swift-evolution@swift.org> wrote: >>>>>>>>>> >>>>>>>>>>> >>>>>>>>>>> On Aug 15, 2016, at 4:09 PM, Charlie Monroe < >>>>>>>>>>> char...@charliemonroe.net> 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 >>>>>>>>>>> swift-evolution@swift.org >>>>>>>>>>> https://lists.swift.org/mailman/listinfo/swift-evolution >>>>>>>>>> >>>>>>>>>> >>>>>> >>>>>> >>>>> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >> _______________________________________________ >> swift-evolution mailing list >> swift-evolution@swift.org >> https://lists.swift.org/mailman/listinfo/swift-evolution >> >
_______________________________________________ swift-evolution mailing list swift-evolution@swift.org https://lists.swift.org/mailman/listinfo/swift-evolution