<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><div id="AppleMailSignature">An idea that I've been kicking around would be to to replace if-(let/var/case)-where, guard-(let/var/case)-where with:</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when &lt;pattern&gt; where &lt;condition&gt; {}</div><div id="AppleMailSignature">guard when &lt;pattern&gt; where &lt;condition&gt; else {}</div><div id="AppleMailSignature">if &lt;condition&gt; {} else {}</div><div id="AppleMailSignature">guard &lt;condition&gt; else {}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">This seems pretty similar to the original design that Chris mentioned and which was rejected, but without it living inside of the "if-case" construct - instead "when" exists as its own kind of statement so "if" and "guard" can revert to a more standard form without binding / pattern matching.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">"When" statement's patterns would allow some new variations to try to solve the pain points:</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">let foo: String?</div><div id="AppleMailSignature">var bar: String? = "thing"</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when let exists = foo where exists == "hi" {</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>// "foo" is still optional, not shadowed, "exists" only valid in this scope</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when foo where foo == "hi" {</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>// "foo" is a shadowed "let" because "foo" was originally a "let"</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when bar where bar == "thing" {</div><div id="AppleMailSignature">&nbsp;<span class="Apple-tab-span" style="white-space:pre">        </span>// "bar" is modeled like an inout and is mutable here because "bar" was a "var"</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>// so changes to "bar" here will be set back to the outer "bar" when the scope ends&nbsp;</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when var exists = foo {</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>// "exists" is mutable local copy and only exists in this scope</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when var bar = bar {</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>// "bar" is a mutable shadowed copy of the outer "bar" and only exists in this scope</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">when case .thing(associated: value) = someEnumProperty {</div><div id="AppleMailSignature"><span class="Apple-tab-span" style="white-space:pre">        </span>print(value)</div><div id="AppleMailSignature">}</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">All of these patterns would also apply to the guard variants as well with the obvious changes to the scoping.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">I hope this isn't similar to the bind thread discussions since I haven't had time to keep up with everything there, but thought I'd toss it out here since it seemed to be on topic-ish.</div><div id="AppleMailSignature"><br></div><div id="AppleMailSignature">l8r</div><div id="AppleMailSignature">Sean</div><br>Sent from my iPad</div><div><br>On Feb 3, 2016, at 10:41 PM, Taras Zakharko via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>&gt; wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8"><br class=""><div><blockquote type="cite" class=""><div class="">On 04 Feb 2016, at 05:03, Jonathan Tang &lt;<a href="mailto:jonathan.d.tang@gmail.com" class="">jonathan.d.tang@gmail.com</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><div dir="ltr" class="">FWIW, I don't see any problems with the current "if let x = ... " syntax or behavior.&nbsp; I view it as a mainstream language finally implementing anaphoric-if (as described in Paul Graham's _On Lisp_), and the unwrapping seems like a natural consequence of the semantics, because what else *could* it do?&nbsp; The if-statement needs to test on something; it seems natural to me that the if tests for optional == nil, and then the let binds the payload of the optional if it matches.</div></div></blockquote><div><br class=""></div><div>To be honest, I agree. But the bind threads reveals that many consider the current if let less transparent, so it makes sense to discuss alternatives.</div><div><br class=""></div><div>One problem I can see with privileging optionals binding in conditional statements however, &nbsp;is the inability to bind non-optionals. That would be quite useful sometimes. E.g. in conditionals:</div><div><br class=""></div><div>&nbsp; if let x = optional_value, y = some_fun_returning_non_optional() where x &gt; y {}</div><div><br class=""></div><div>forcing one to write something like this instead (or a nested if)</div><div><br class=""></div><div>&nbsp; myif: if x = optional_value {</div><div>&nbsp; &nbsp; let y = some_fun_returning_non_optional()</div><div>&nbsp; &nbsp; guard x &gt; y else {break myif}</div><div>&nbsp; &nbsp; ...</div><div>&nbsp;}</div><div><br class=""></div><div>Same goes for guard, it would be nice to do something like</div><div><br class=""></div><div>&nbsp; guard let&nbsp;</div><div>&nbsp; &nbsp; &nbsp; x = optional1,</div><div>&nbsp; &nbsp; &nbsp; y = x.optional2,</div><div>&nbsp; &nbsp; &nbsp; z = x.non_optional,</div><div>&nbsp; &nbsp; &nbsp; w = z.optional3</div><div>&nbsp; else {</div><div>&nbsp; &nbsp; // failed to initialise&nbsp;</div><div>&nbsp;}</div><div><br class=""></div><div>If I remember correctly, I encountered this problem when playing with Metal, where I wanted to initialise a bunch of relevant variables in one go, but had to break up my guards into a number of blocks. This breaks the program logic.&nbsp;</div><div><br class=""></div><div>— Taras</div><br class=""><blockquote type="cite" class=""><div class=""><div dir="ltr" class=""><div class=""><br class=""></div><div class="">I wouldn't rule out there being something better, but I'm -1 on all the proposals I've seen so far to change it.</div></div><div class="gmail_extra"><br class=""><div class="gmail_quote">On Wed, Feb 3, 2016 at 7:49 PM, Taras Zakharko via swift-evolution <span dir="ltr" class="">&lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt;</span> wrote:<br 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" class="">I already suggested this in the bind thread but I guess it was either not interesting or people missed it, so here it goes again :)<div class=""><br class=""></div><div class="">What about changing the syntax of optional binding such that the optional unwrapping becomes explicit? I.e. instead of&nbsp;</div><div class=""><br class=""></div><div class="">&nbsp; if let x = some_optional { }</div><div class=""><br class=""></div><div class="">one writes</div><div class=""><br class=""></div><div class="">&nbsp; if let x = some_optional! { }</div><div class=""><br class=""></div><div class="">Essentially, the point of this suggestion is that the runtime error generated by unwrapping an empty Optional is instead treated as condition failure in a conditional statement. While there is some typing overhead over the current syntax, I see a number of potential benefits of this approach:</div><div class=""><br class=""></div><div class="">&nbsp;1. It is in line with the current semantics and syntax of optional unwrapping (does not introduce any new syntagm)</div><div class="">&nbsp;2. It makes the unwrapping operation explicit (thus addressing the basic criticism from the bind discussion)</div><div class="">&nbsp;3. It frees variable declaration of the contextual polisemy (i.e. let and var have the same semantics as nowhere else, there is no ‘unwrapping’ magic)</div><div class="">&nbsp;4. The change is minimal compare to what we have now and can be easily ported automatically</div><div class=""><br class=""></div><div class="">Potential issues:</div><div class=""><br class=""></div><div class="">&nbsp;1. One character typing overhead — but I dot think that should matter. I always had the impression that Swift favours clarity over compactness (which is a good thing IMO)</div><div class="">&nbsp;2. it allows syntactic ambiguity with optional chaining. E.g. if let x = a.b?.c! { } and if let x = a.b!.c would have the same meaning. Then again, this ambiguity already exits in the language to begin with.&nbsp;</div><div class=""><br class=""></div><div class="">— Taras</div><div class=""><div class="h5"><div class=""><br class=""></div><div class=""><div class=""><blockquote type="cite" class=""><div class="">On 04 Feb 2016, at 01:25, Chris Lattner via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class=""><div class=""><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" class=""><blockquote type="cite" class=""><div class=""><br class="">On Feb 3, 2016, at 3:47 PM, Jordan Rose via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class=""><div class=""><div style="word-wrap:break-word" class=""><div class="">Data point (which Chris brought up already, I think?): We tried this* and got a<span class="">&nbsp;</span><i class="">lot</i>&nbsp;of negative feedback. Optionals are unwrapped too often for people to be comfortable writing "if let name? = optionalCondition”.</div></div></div></blockquote><div class=""><br class=""></div><div class="">Yes, I even implemented this and it was in the compiler for awhile, then later ripped it back out.&nbsp; You can find the history in git.&nbsp; I would guess that this all happened in ~March 2015.</div><div class=""><br class=""></div><div class="">-Chris</div><div class=""><br class=""></div><blockquote type="cite" class=""><div class=""><div style="word-wrap:break-word" class=""><div class=""><br class=""></div><div class="">It may be more uniform and even more pedantically correct, but our users hated it.</div><div class=""><br class=""></div><div class="">Jordan</div><div class=""><br class=""></div><div class="">* The actual thing we tried only allowed patterns that began with 'let', but that's close enough.</div><div class=""><br class=""></div><br class=""><div class=""><blockquote type="cite" class=""><div class="">On Feb 3, 2016, at 15:36, Brent Royal-Gordon via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class=""><div class=""><div class="">This is a continuation of and alternative proposal to "The bind thread", which seems to have petered out without consensus.<br class=""><br class="">Currently there are three forms of `if` statement (and `guard` and `while`, but for simplicity I'll just say `if` throughout this discussion):<br class=""><br class=""><span style="white-space:pre-wrap" class="">        </span>if booleanCondition<br class=""><span style="white-space:pre-wrap" class="">        </span>if let name = optionalCondition<br class=""><span style="white-space:pre-wrap" class="">        </span>if case pattern = expression<br class=""><br class="">The boolean condition form is fine, but there are flaws in the other two. `if let` is unprincipled and doesn't really say what it does; `if case` is bulky and rarely used.*<span class="">&nbsp;</span><br class=""><br class="">One very interesting thing about `if case`, too, is that it can actually do optional unwrapping:<br class=""><br class=""><span style="white-space:pre-wrap" class="">        </span>if case let name? = optionalCondition<br class=""><br class="">This avoids the problems with `if let`—it's principled (it comes from a larger language feature) and it explicitly says it's handling optionality—but it still runs up against `if case`'s rarity and wordiness.<br class=""><br class="">So what I suggest is that we drop the `if let` form entirely and then drop the `case` keyword from `if case`. Pattern-matching conditions can still be distinguished from boolean conditions because boolean conditions can't contain an `=` operator. This, there would now only be two forms of if:<br class=""><br class=""><span style="white-space:pre-wrap" class="">        </span>if booleanCondition<br class=""><span style="white-space:pre-wrap" class="">        </span>if pattern = expression<br class=""><br class="">And the current `if let` is handled elegantly and clearly by existing pattern-matching shorthand, with only one additional character needed:<br class=""><br class=""><span style="white-space:pre-wrap" class="">        </span>if let name? = optionalCondition<br class=""><br class="">I see two complications with this.<br class=""><br class="">The first is that, naively, `if let foo = bar` would still be valid, but would have different and vacuous behavior, since the pattern cannot fail to match. The compiler should probably emit an error or at least a warning when this happens.<br class=""><br class="">The second is our other weird use of the `case` keyword, `for case`, which is now an orphan in the language. I see several ways this could be handled:<br class=""><br class="">1. Drop the `for case` functionality entirely; if you want that behavior, use a pattern-matching `if`.<br class="">2. Replace the loop variable slot in the `for` statement with a pattern. This would force you to put `let` on all simple `for` statements.<br class="">3. Try to automatically distinguish between simple variables/tuples and patterns in this slot. What could possibly go wrong?<br class="">4. Require an equals sign before the `in`, like `for let foo? = in optionalFoos`. Looks a little gross, but it's unambiguous.<br class="">5. Replace `for case` with `for if`, like `for if let foo? in optionalFoos`. This helps flag the unusual conditional behavior of this form of `for`.<br class="">6. Just keep `for case` and don't worry about the fact that it's not parallel to the other statements anymore.<br class=""><br class="">Thoughts on any of this?<br class=""><br class=""><br class=""><br class="">* `if case` also has the problem that the `=` isn't appropriate unless you happen to bind some of the data matched by the pattern, but I don't know how to address that. A prior version of this proposal suggested saying `:=` instead of `=`, with the idea that `:=` could become a general pattern-matching operator, but the people I talked over this post with hated that.<br class=""><br class="">--<span class="">&nbsp;</span><br class="">Brent Royal-Gordon<br class="">Architechies<br class=""><br class="">_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></div></blockquote></div><br class=""></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" target="_blank" class="">swift-evolution@swift.org</a><br class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br 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" class=""><span 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;float:none;display:inline!important" class="">_______________________________________________</span><br 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" class=""><span 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;float:none;display:inline!important" class="">swift-evolution mailing list</span><br 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" class=""><a href="mailto:swift-evolution@swift.org" 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" target="_blank" class="">swift-evolution@swift.org</a><br 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" class=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" 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" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a></div></blockquote></div><br class=""></div></div></div></div><br class="">_______________________________________________<br class="">
swift-evolution mailing list<br class="">
<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
<br class=""></blockquote></div><br class=""></div>
</div></blockquote></div><br class=""></div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></body></html>