<div dir="ltr"><div class="gmail_extra"><div class="gmail_quote">On Mon, Aug 15, 2016 at 12:07 PM, Xiaodi Wu <span dir="ltr">&lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class="">On Mon, Aug 15, 2016 at 11:43 AM, Justin Jia <span dir="ltr">&lt;<a href="mailto:justin.jia.developer@gmail.com" target="_blank">justin.jia.developer@gmail.<wbr>com</a>&gt;</span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div>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?</div></div></div></blockquote><div><br></div></span><div>No, it certainly doesn&#39;t! I&#39;m saying that you haven&#39;t come up with a solution to a known problem with the idea.</div><div><div class="h5"><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><br></div><div>Assuming we have the following declaration:</div><div><br></div><div>```</div><div>func foo(a: Int, b: Int?, c: Int, d: Int?) -&gt; Int</div><div>```</div><div><br></div><div>For this:</div><div><br></div><div>```</div><div>let z = foo(a: f1(), b: f2()?, c: f3(), d: f4()?) // z becomes optional</div><div>```</div><div><br></div><div>We have a few different “possible solutions”:</div><div><br></div><div>1. Short-circuiting from left to right. This is equivalent to:</div><div><br></div><div>```</div><div>var z: Int? = nil</div><div>let a = f1()</div><div>guard let b = f2() else { return }</div><div>let c = f3()</div><div>guard let d = f4() else { return }</div><div>z = foo(a: a, b: b, c: c, d: d)</div><div>```</div><div><br></div><div>2. Short-circuiting from left to right for optionals. Then evaluate non-optional parameters. This is equivalent to:</div><div><br></div><div>```</div><div>var z: Int? = nil</div><div>guard let b = f2() else { return }</div><div>guard let d = f4() else { return }</div><div>let a = f1()</div><div>let c = f3()</div><div>z = foo(a: a, b: b, c: c, d: d)</div><div>```</div><div><br></div><div>3. Do not short-circuiting.</div><div><br></div><div>```</div><div>var z: Int? = nil</div><div>let a = f1()</div><div>let optionalB = f2()</div><div>let c = f3()</div><div>let optionalD = f4()</div><div>guard let b = optionalB else { return }</div><div>guard let d = optionalD else { return }</div><div>z = foo(a: a, b: b, c: c, d: d)</div><div>```</div><div><br></div><div>Like I said before, I agree that there is no intuitive solution to this problem. However, I&#39;m still not convinced that this feature is *not important*.</div><div><br></div><div>Thank you for pointing out the problem to me. I didn&#39;t notice it at the time I wrote my first email. I really appreciate that. However, instead of saying I don&#39;t know which is the best solution so let&#39;s assume the core team made the right decision, we should discuss whether 1, 2, 3 is the best solution. Or you can convince me we don&#39;t *need* this feature.</div></div></div></blockquote><div><br></div></div></div><div>I&#39;m going to convince you that 1, 2, and 3 are all bad solutions. Thus, this feature won&#39;t fly.</div><div>The fundamental issue is that having this sugar means that I can no longer reason about the order in which code is executed. An innocuous statement such as `print(a(), b(), c(), d())`, once you mix in your proposed `?` syntax with some but not all of these function calls, might have d() executed before a(), after a(), or not at all. This is greatly damaging to the goal of writing clear, understandable code.</div><span class=""><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><br></div><div>Back to the original topic.</div><div><br></div><div>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.</div><div><br></div><div>-</div><div><br></div><div>Below is the reason why I think this feature is important (quoted from another email).</div><div><br></div><div>The problem with `if let` is you need to call the function inside { }.</div><div><br></div><div>```</div><div>/* code 1 */</div><span><div>if let x = x, let y = y {</div></span><div>    /* code 2, depends on x and y to be non-optional */</div><div>    let z = foo(x, y)</div><div>    if let z = z {</div><div>        bar(z)</div><div>    }</div><div>    /* code 3, depends on x and y to be non-optional */</div><div>}</div><div>/* code 4 */</div><div>```</div><div><br></div><div>I can&#39;t use `guard` for this situation because guard will force me to leave the entire function.</div></div></div></blockquote></span></div></div></div></blockquote><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><span class=""><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><div><br></div><div>```</div><div>/* code 1 */</div><span><div>guard let x = x, y = y else { return }</div></span><div>/* code 2, depends on x and y to be non-optional */</div><span><div>guard let z = foo(x, y) else { return }</div><div>bar(z)</div></span><div>/* code 3, depends on x and y to be non-optional */ &lt;- This won&#39;t execute if z is nil</div><div>/* code 4 */ &lt;- This won&#39;t execute if x, y or z is nil</div><span><div>```</div></span></div></div></blockquote><div><br></div></span><div>Then surround it with a do block.</div><div><br></div><div>```</div><div>out: do {</div><div>  guard foo else { break out }</div><div>  guard bar else { break out }</div><div>  /* other code */</div><div><div class="h5"><div>}</div><div>```</div></div></div></div></div></div></blockquote><div><br></div><div>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:</div><div><br></div><div>```</div><div>defer { /* code 4 */ }</div><div>guard let x = x, let y = y else { return }</div><div>/* code 2 */</div><div>/* code 3 */</div><div>```</div><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div class="h5"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div><span><div><br></div><div>What I really want is some like this:</div><div><br></div><div>```</div><div>/ * code 1 */</div></span><span><div>let z = foo(x?, y?)</div></span><div>/* code 2, depends on x and y to be non-optional, use x? and y? */</div><div>bar(z?)</div><div>/* code 3, depends on x and y to be non-optional, use x? and y? */</div><div>/* code 4 */</div><div>```</div><div>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).</div><div><br></div><div>Sincerely,</div><div>Justin</div></div><div><div><div><br></div><div><br></div><div><br></div><br><div><blockquote type="cite"><div>On Aug 15, 2016, at 11:41 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:</div><br><div><div style="white-space:pre-wrap">What do you mean, limited to variables? What about a computed property? You will have the same problem.<br><br>I&#39;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.<br></div><br><div class="gmail_quote"><div dir="ltr">On Mon, Aug 15, 2016 at 04:56 Justin Jia &lt;<a href="mailto:justin.jia.developer@gmail.com" target="_blank">justin.jia.developer@gmail.co<wbr>m</a>&gt; wrote:<br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="auto"><div></div><div style="direction:inherit">IMO I don&#39;t this bar should be evaluated unless we decide if let can accept non-optional values. </div><div style="direction:inherit"><br></div><div style="direction:inherit">Actually, what if we allow if let to accept non-optional values?</div><div style="direction:inherit"><br></div><div style="direction:inherit"><span style="background-color:rgba(255,255,255,0)">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. </span></div><div style="direction:inherit"><br></div><div style="direction:inherit">Btw, do you think this is still something nice to have if we limit this syntax to only variables?</div></div><div dir="auto"><div><div style="direction:inherit"><br></div>On Aug 15, 2016, at 4:59 PM, Xiaodi Wu &lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><div dir="ltr">On Mon, Aug 15, 2016 at 3:55 AM, Xiaodi Wu <span dir="ltr">&lt;<a href="mailto:xiaodi.wu@gmail.com" target="_blank">xiaodi.wu@gmail.com</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div><div>On Mon, Aug 15, 2016 at 3:25 AM, Justin Jia via swift-evolution <span dir="ltr">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt;</span> wrote:<br></div></div><div class="gmail_extra"><div class="gmail_quote"><div><div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><br><div><blockquote type="cite"><div>On Aug 15, 2016, at 4:09 PM, Charlie Monroe &lt;<a href="mailto:charlie@charliemonroe.net" target="_blank">charlie@charliemonroe.net</a>&gt; wrote:</div><br><div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">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, </div><span><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">if let x = bar(42), y = baz(42) { ... }</div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div></span><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">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 </div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">foo(bar(42)?, baz(42)?) </div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><br></div><div style="font-family:Helvetica;font-size:12px;font-style:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px">evaluate both arguments even if the first one is nil, making it incosistent with the rest of the language?</div></div></blockquote></div><br><div>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.</div><div><br></div><div>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.</div><span><div><br></div><div>If they want to opt-out this behavior, they can always write:</div><div><br></div><div>```</div><div>let x = bar(42)</div><div>let y = baz(42)</div></span><div>foo(x?, y?)</div><div>```</div></div></blockquote><div><br></div></div></div><div>Well, that was just the easy part. Now, suppose bar is the function that isn&#39;t optional.</div><div><br></div><div>```</div><div>foo(bar(42), baz(42)?)</div><div>```</div><div><br></div><div>Is bar evaluated if baz returns nil? If you want this syntax to be sugar for if let, then the answer is yes.</div></div></div></div></blockquote><div><br></div><div>s/yes/no/</div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>If short-circuiting works left-to-right, then the answer is no.</div></div></div></div></blockquote><div><br></div><div>s/no/yes/ </div><div><br></div><div>(See? Confusing.)</div><div> <br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div dir="ltr"><div class="gmail_extra"><div class="gmail_quote"><div>This is very confusing, and there is no good intuitive answer. <br></div><span><div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div style="word-wrap:break-word"><div></div></div><br>______________________________<wbr>_________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailma<wbr>n/listinfo/swift-evolution</a><br>
<br></blockquote></span></div><br></div></div>
</blockquote></div><br></div></div>
</div></blockquote></div></blockquote></div>
</div></blockquote></div><br></div></div></div></blockquote></div></div><br></div></div>
</blockquote></div><br></div></div>