<div dir="ltr">On Sun, Jun 12, 2016 at 6:46 AM, Brent Royal-Gordon via swift-evolution <span dir="ltr"><<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>></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 style="word-wrap:break-word"><div>When I suggested this syntax in the acceptance thread for SE-0099, Chris said it should be written up as a proposal. I'm sure this will get lost in the WWDC shuffle, but here goes.</div><div><div><form accept-charset="UTF-8" action="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920/file/e4c68fd01167364a56e006faac46ec94278c8002" method="post" target="_blank" onsubmit="try {return window.confirm("You are submitting information to an external page.\nAre you sure?");} catch (e) {return false;}"><div style="margin-top:20px;margin-bottom:15px;border:1px solid rgb(221,221,221);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px"><div><h1 style="font-size:2.25em;margin-right:0px;margin-bottom:16px;margin-left:0px;line-height:1.2;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238);margin-top:0px!important">Tuple-Based Compound Optional Binding</h1><ul style="padding-left:2em;margin-top:0px;margin-bottom:16px"><li>Proposal: TBD</li><li>Author: <a href="https://github.com/brentdax" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">Brent Royal-Gordon</a></li><li>Status: TBD</li><li>Review manager: TBD</li></ul><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#introduction" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Introduction</h2><p style="margin-top:0px;margin-bottom:16px">This proposal enhances optional binding with a new, tuple-based syntax for binding multiple values. It replaces functionality lost in SE-0099 with a syntax compatible with the new design.</p><p style="margin-top:0px;margin-bottom:16px">Swift Evolution Discussion: <a href="http://thread.gmane.org/gmane.comp.lang.swift.evolution/19452/focus=20139" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">[Accepted with Revision] SE-0099 Restructuring Condition Clauses</a></p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#motivation" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Motivation</h2><p style="margin-top:0px;margin-bottom:16px">In Swift 2, it was possible to bind multiple optional values in a single <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">if let</code>, <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">guard let</code>, or <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">while let</code> clause:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> a <span style="color:rgb(167,29,93)">=</span> opt1, b <span style="color:rgb(167,29,93)">=</span> opt2, c <span style="color:rgb(167,29,93)">=</span> opt3 <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px"><a href="https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none" target="_blank">SE-0099</a> simplified the syntax of conditional statements, but removed this feature so that <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">,</code> could instead separate different conditional clauses. Code like this must now use three separate optional binding clauses:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> a <span style="color:rgb(167,29,93)">=</span> opt1, <span style="color:rgb(167,29,93)">let</span> b <span style="color:rgb(167,29,93)">=</span> opt2, <span style="color:rgb(167,29,93)">let</span> c <span style="color:rgb(167,29,93)">=</span> opt3 <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">The similar <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case</code> clause sidesteps this problem because it can pattern-match tuples. Hence, you can put several patterns in a tuple on the left side of the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">=</code>, and a matching number of values in a tuple on the right side, and match them all with one <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case</code> clause:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">case</span> (<span style="color:rgb(167,29,93)">.</span><span style="color:rgb(167,29,93)">none</span>, <span style="color:rgb(167,29,93)">.</span><span style="color:rgb(167,29,93)">none</span>, <span style="color:rgb(167,29,93)">.</span><span style="color:rgb(167,29,93)">none</span>) <span style="color:rgb(167,29,93)">=</span> (opt1, opt2, opt3) <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">This doesn't conflict with the clause separation syntax because the commas are within parentheses. However, the analogous syntax for optional bindings is not permitted:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> (a, b, c) <span style="color:rgb(167,29,93)">=</span> (opt1, opt2, opt3) <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }
<span style="color:rgb(150,152,150)">// error: initializer for conditional binding must have </span>
<span style="color:rgb(150,152,150)">// Optional type, not '(Int?, Int?, Int?)' (aka </span>
<span style="color:rgb(150,152,150)">// '(Optional<Int>, Optional<Int>, Optional<Int>)')</span></pre></div><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#proposed-solution" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Proposed Solution</h2><p style="margin-top:0px;margin-bottom:16px">We should extend optional binding clauses to permit a tuple of optional values on the right of the <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">=</code> and a tuple of constants with identical arity on the left. Swift should test each element of the tuple on the right, and if none of them are <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">nil</code>, bind them to the constants on the left.</p><p style="margin-top:0px;margin-bottom:16px">Nothing in this proposal should change the way optional binding handles an <em>optional tuple</em> <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">(T, U)?</code>, as opposed to a <em>tuple of optionals</em> <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">(T?, U?)</code>. Even an optional tuple of optionals <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">(T?, U?)?</code> should continue to be handled as before.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#detailed-design" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Detailed Design</h2><p style="margin-top:0px;margin-bottom:16px">No change to the formal grammar is necessary, as the <em>pattern</em> and <em>initializer</em> productions in the <em>optional-binding-head</em> rule can already match tuples:</p><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:16px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px"><code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;padding:0px;margin:0px;background-color:transparent;border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal;border:0px;display:inline;overflow:visible;line-height:inherit;word-wrap:normal">optional-binding-head : 'let' pattern initializer
</code></pre><p style="margin-top:0px;margin-bottom:16px">Rather, Sema should be modified to detect this situation and generate appropriate code. Currently, TypeCheckPattern.cpp essentially converts <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">let a = opt1</code> into <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case let a? = opt1</code>; if this proposal is accepted, it should similarly convert <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">let (a, b) = (opt1, opt2)</code> into <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case let (a?, b?) = (opt1, opt2)</code>.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#edge-cases" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Edge cases</h3><h4 style="margin-top:1em;margin-bottom:16px;line-height:1.4;font-size:1.25em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#nested-tuples-of-optionals" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Nested tuples-of-optionals</h4><p style="margin-top:0px;margin-bottom:16px">Permitting deeper pattern matching of nested tuples is highly precedented by pattern matching, but is a niche feature. It should be supported if easily achievable.</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> (a, (b, c)) <span style="color:rgb(167,29,93)">=</span> (opt1, (opt2, opt3)) <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><h4 style="margin-top:1em;margin-bottom:16px;line-height:1.4;font-size:1.25em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#expressions-returning-tuples-of-optionals" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Expressions returning tuples of optionals</h4><p style="margin-top:0px;margin-bottom:16px">Ideally, optional bindings whose <em>initializer</em> is an expression evaluating to a tuple of optionals would be supported:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">let</span> tuple <span style="color:rgb(167,29,93)">=</span> (opt1, opt2)
<span style="color:rgb(167,29,93)">if</span> <span style="color:rgb(167,29,93)">let</span> (a, b) <span style="color:rgb(167,29,93)">=</span> tuple { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">However, I'm not sure if Swift will have pinned down the type of the initializer at the point where it's generating the pattern. If this would be difficult or impossible to implement, Swift should continue to interpret code like this as attempting to bind an optional tuple, rather than a tuple of optionals.</p></div></div></form></div></div></div></blockquote><div><br></div><div>I think this proposal is definitely worthy of consideration (and implementation). I hesitate that what works or not is being proposed partly on the basis of whether it's difficult to implement or not. If I could offer a suggestion as to exactly which edge cases should work, I think it should be based on this guideline that can be articulated cleanly:</div><div><br></div><div>Given `if let (a, b, c)...` or any other variation or edge case, transform in your mind's eye to `if case let (a?, b?, c?)...`. That is, append `case` before `let` and then append `?` immediately after each constant so introduced. If the `if case let...` version would work, so should the `if let...` version. By that rule of thumb, `if case let (a?, (b?, c?)) = (opt1, (opt2, opt3))` would work if I'm not mistaken, as would `if case let (a?, b?) = tuple`, but `if case let tuple? = (opt1, opt2)` would not and thus neither should `if let tuple = (opt1, opt2)`.</div><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><form accept-charset="UTF-8" action="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920/file/e4c68fd01167364a56e006faac46ec94278c8002" method="post" target="_blank" onsubmit="try {return window.confirm("You are submitting information to an external page.\nAre you sure?");} catch (e) {return false;}"><div style="margin-top:20px;margin-bottom:15px;border:1px solid rgb(221,221,221);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px"><div><h4 style="margin-top:1em;margin-bottom:16px;line-height:1.4;font-size:1.25em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#single-name-patterns" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Single-name patterns</h4><p style="margin-top:0px;margin-bottom:16px">In theory, Swift could allow you to bind a tuple of optionals to a single constant:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">if</span> <span style="color:rgb(167,29,93)">let</span> tuple <span style="color:rgb(167,29,93)">=</span> (opt1, opt2) { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">However, this seems error-prone; the pattern doesn't draw a very clear picture of the value being operated upon, so you could easily misinterpret it as binding an optional tuple. Because of this ambiguity, Swift should always interpret this construct as binding an optional tuple, rejecting it with a type error if necessary.</p><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#impact-on-existing-code" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Impact on Existing Code</h2><p style="margin-top:0px;margin-bottom:16px">This proposal is additive compared to SE-0099, but in combination with it, essentially replaces the Swift 2.2 compound binding syntax with a different, incompatible one. When moving directly from Swift 2.2, the migrator should convert old-style compound optional binding clauses:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> a <span style="color:rgb(167,29,93)">=</span> opt1, b <span style="color:rgb(167,29,93)">=</span> opt2, c <span style="color:rgb(167,29,93)">=</span> opt3 <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">Into the new, tuple-based ones:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> (a, b, c) <span style="color:rgb(167,29,93)">=</span> (opt1, opt2, opt3) <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><p style="margin-top:0px;margin-bottom:16px">The "one-<code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">let</code>-per-binding" syntax remains compatible with both Swift 2.2 and Swift 3, so projects which must support both can still perform multiple optional bindings in a single <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">if</code> statement without resorting to an <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">#if swift(>=3.0)</code> build configuration:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> a <span style="color:rgb(167,29,93)">=</span> opt1, <span style="color:rgb(167,29,93)">let</span> b <span style="color:rgb(167,29,93)">=</span> opt2, <span style="color:rgb(167,29,93)">let</span> c <span style="color:rgb(167,29,93)">=</span> opt3 <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><h2 style="margin-top:1em;margin-bottom:16px;line-height:1.225;font-size:1.75em;padding-bottom:0.3em;border-bottom-width:1px;border-bottom-style:solid;border-bottom-color:rgb(238,238,238)"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#alternatives-considered" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1" target="_blank"><u></u><u></u><u></u><u></u></a>Alternatives Considered</h2><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#not-accepting-this-proposal" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Not accepting this proposal</h3><p style="margin-top:0px;margin-bottom:16px">This proposal does not add new functionality; it merely removes keyword clutter. However, it offers a convenient replacement for a commonly-used feature which has just been removed as a result of grammatical ambiguity, not user confusion or lack of utility.</p><h3 style="margin-top:1em;margin-bottom:16px;line-height:1.43;font-size:1.5em"><a href="https://gist.github.com/brentdax/46c340c967358589ade5351531ac8920#providing-similar-standard-library-functionality" style="background-color:transparent;color:rgb(64,120,192);text-decoration:none;display:inline-block;padding-right:2px;line-height:1.2" target="_blank"><u></u><u></u><u></u><u></u></a>Providing similar standard library functionality</h3><p style="margin-top:0px;margin-bottom:16px">Rather than including this functionality in the compiler, the standard library could provide a series of functions like:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">all</span><T, U>(<span style="color:rgb(121,93,163)">_</span> <span style="color:rgb(51,51,51)">t</span>: T?, <span style="color:rgb(121,93,163)">_</span> <span style="color:rgb(51,51,51)">u</span>: U?) <span style="color:rgb(167,29,93)">-></span> (T, U)? { <span style="color:rgb(167,29,93)">...</span> }
<span style="color:rgb(167,29,93)">public</span> <span style="color:rgb(167,29,93)">func</span> <span style="color:rgb(121,93,163)">all</span><T, U, V>(<span style="color:rgb(121,93,163)">_</span> <span style="color:rgb(51,51,51)">t</span>: T?, <span style="color:rgb(121,93,163)">_</span> <span style="color:rgb(51,51,51)">u</span>: U?, <span style="color:rgb(121,93,163)">_</span> <span style="color:rgb(51,51,51)">v</span>: V?) <span style="color:rgb(167,29,93)">-></span> (T, U, V)? { <span style="color:rgb(167,29,93)">...</span> }
<span style="color:rgb(150,152,150)">// etc.</span></pre></div><p style="margin-top:0px;margin-bottom:16px">These could then be used in a similar fashion to this proposal:</p><div style="margin-bottom:16px"><pre style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;margin-top:0px;margin-bottom:0px;line-height:1.45;word-wrap:normal;padding:16px;overflow:auto;background-color:rgb(247,247,247);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px;word-break:normal"><span style="color:rgb(167,29,93)">guard</span> <span style="color:rgb(167,29,93)">let</span> (a, b, c) <span style="color:rgb(167,29,93)">=</span> all(opt1, opt2, opt3) <span style="color:rgb(167,29,93)">else</span> { <span style="color:rgb(167,29,93)">...</span> }</pre></div><div style="margin-top:0px;margin-bottom:0px!important">However, because we do not have variadic generics, we would need to provide a set of overloads for different arities, and our support would be limited to the arities we chose to provide. (Support for tuples, as opposed to separate parameters, would require a second set of overloads). Meanwhile, the tuple matching syntax is already precedented in <code style="font-family:Consolas,'Liberation Mono',Menlo,Courier,monospace;font-size:14px;padding:0.2em 0px;margin:0px;background-color:rgba(0,0,0,0.0392157);border-top-left-radius:3px;border-top-right-radius:3px;border-bottom-right-radius:3px;border-bottom-left-radius:3px">case</code> conditionals, so extending it seems pretty natural. Providing this in the compiler seems like the right solution.</div></div></div></form></div></div><span class="HOEnZb"><font color="#888888"><div><br></div><br><div>
<span style="border-collapse:separate;line-height:normal;border-spacing:0px"><div><div style="font-size:12px">-- </div><div style="font-size:12px">Brent Royal-Gordon</div><div style="font-size:12px">Architechies</div></div></span>
</div>
<br></font></span></div><br>_______________________________________________<br>
swift-evolution mailing list<br>
<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a><br>
<a href="https://lists.swift.org/mailman/listinfo/swift-evolution" rel="noreferrer" target="_blank">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br>
<br></blockquote></div><br></div></div>