<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Sep 3, 2017, at 1:35 PM, Xiaodi Wu via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:</div><br class="Apple-interchange-newline"><div class="">The desired behavior was the major topic of controversy during review; I’m wary of revisiting this topic as we are essentially relitigating the proposal.<br class=""><br class="">To start off, the premise, if I recall, going into review was that the author **rejected** the notion that pattern matching should mirror creation. </div></blockquote><div><br class=""></div><div>Original author here. Here’s the review thread, for context: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170306/thread.html#33626" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170306/thread.html#33626</a></div><div><br class=""></div><div>While I did state declaration and pattern should be considered separately, it was an defense for the pattern syntax as in that specific revision of the proposal. In my heart of hearts, I was in favor of mandatory labels all along. In fact, it’s what the 1st revision of the proposal wanted: <a href="https://github.com/apple/swift-evolution/blob/43ca098355762014f53e1b54e02d2f6a01253385/proposals/0155-normalize-enum-case-representation.md" class="">https://github.com/apple/swift-evolution/blob/43ca098355762014f53e1b54e02d2f6a01253385/proposals/0155-normalize-enum-case-representation.md</a></div><div><br class=""></div><div>The strictness of label requirements got progressively knocked down as the proposal graduated from 1st to 2nd revision to acceptance rationale 😅.</div><br class=""><blockquote type="cite" class=""><div class="">I happen to agree with you on this point, but it was not the prevailing argument. Fortunately, we do not need to settle this to arrive at some clarity for the issues at hand.<br class=""><br class="">From a practical standpoint, a requirement for labels in all cases would be much more source-breaking, whereas the proposal as it stands would allow currently omitted labels to continue being valid. Moreover, and I think this is a worthy consideration, one argument for permitting the omission of labels during pattern matching is to encourage API designers to use labels to clarify initialization without forcing its use by API consumers during every pattern matching operation.<br class=""><br class="">In any case, the conclusion reached is precedented in the world of functions:<br class=""><br class=""> func g(a: Int, b: Int) { ... }<br class=""> let f = g<br class=""> f(1, 2)<br class=""><br class=""><div class="gmail_quote"><div dir="ltr" class="">On Sun, Sep 3, 2017 at 15:13 Robert Widmann via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> wrote:<br class=""></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" class="">Hello Swift Evolution,<div class=""><br class=""></div><div class="">I took up the cause of implementing <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md" target="_blank" class="">SE-0155</a>, and am most of the way through the larger points of the proposal. One thing struck me when I got to the part about <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md#pattern-consistency" target="_blank" class="">normalizing the behavior of pattern matching</a>. The Core Team indicated in their <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170417/035972.html" target="_blank" class="">rationale</a> that the proposal’s suggestion that a variable binding sub in for a label was a little much as in this example:</div><div class=""><br class=""></div><div class=""><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;background-color:rgb(255,255,255)" class=""><span style="color:#ba2da2" class="">enum</span> Foo {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;background-color:rgb(255,255,255)" class=""> <span style="color:#ba2da2" class="">case</span> foo(x: Int, y: Int)</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;background-color:rgb(255,255,255)" class="">}</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x: x, y: y) {} </span>// Fine! Labels match and are in order</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x, y: y) {} </span>// Bad! Missing label 'x'</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x, y) {} </span>// Fine? Missing labels, but variable names match labels</div></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><br class=""></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><span style="font-family: Helvetica; font-size: 12px;" class="">They instead suggested the following behavior:</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0);background-color:rgb(255,255,255)" class=""><span style="font-family: Helvetica; font-size: 12px;" class=""><br class=""></span></div><div style="margin:0px;line-height:normal;background-color:rgb(255,255,255)" class=""><div style="font-family: Menlo; font-size: 11px; margin: 0px; line-height: normal;" class=""><span style="color:#ba2da2" class="">enum</span> Foo {</div><div style="font-family: Menlo; font-size: 11px; margin: 0px; line-height: normal;" class=""> <span style="color:#ba2da2" class="">case</span> foo(x: Int, y: Int)</div><div style="font-family: Menlo; font-size: 11px; margin: 0px; line-height: normal;" class="">}</div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x: x, y: y) {} </span>// Fine! Labels match and are in order</div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x, y: y) {} </span>// Bad! Missing label 'x'</div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x, y) {} </span>// Fine? Missing labels, and full name of case is unambiguous</div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><br class=""></div><div style="margin:0px;line-height:normal" class=""><div style="margin:0px;line-height:normal" class="">Which, for example, would reject this:</div><div style="margin:0px;line-height:normal" class=""><br class=""></div><div style="margin:0px;line-height:normal" class=""><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo" class=""><span style="color:#ba2da2" class="">enum</span> Foo {</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo" class=""> <span style="color:#ba2da2" class="">case</span> foo(x: Int, y: Int) <span style="color:#008400" class="">// Note: foo(x:y:)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo" class=""> <span style="color:#ba2da2" class="">case</span> foo(x: Int, z: Int) <span style="color:#008400" class="">// Note: foo(x:z:)</span></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo" class="">}</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)" class=""><span style="color:#ba2da2" class="">if</span><span style="" class=""> </span><span style="color:#ba2da2" class="">case</span><span style="" class=""> </span><span style="color:#ba2da2" class="">let</span><span style="" class=""> .foo(x, y) {} </span>// Bad! Are we matching foo(x:y:) or foo(x:z:)?</div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)" class=""><br class=""></div><div style="margin:0px;font-size:11px;line-height:normal;font-family:Menlo;color:rgb(0,132,0)" class=""><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">With this reasoning:</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><pre style="white-space:pre-wrap" class=""></pre><blockquote type="cite" class=""><pre style="white-space:pre-wrap" class=""> - While an associated-value label can indeed contribute to the readability of the pattern, the programmer can also choose a meaningful name to bind to the associated value. This binding name can convey at least as much information as a label would.
- The risk of mis-labelling an associated value grows as the number of associated values grows. However, very few cases carry a large number of associated values. As the amount of information which the case should carry grows, it becomes more and more interesting to encapsulate that information in its own struct — among other reasons, to avoid the need to revise every matching case-pattern in the program. Furthermore, when a case does carry a significant number of associated values, there is often a positional conventional between them that lowers the risk of re-ordering: for example, the conventional left-then-right ordering of a binary search tree. Therefore this risk is somewhat over-stated, and of course the programmer should remain free to include labels for cases where they feel the risk is significant.
- It is likely that cases will continue to be predominantly distinguished by their base name alone. Methods are often distinguished by argument labels because the base name identifies an entire class of operation with many possible variants. In contrast, each case of an enum is a kind of data, and its name is conventionally more like the name of a property than the name of a method, and thus likely to be unique among all the cases. Even when cases are distinguished using only associated value labels, it simply means that the corresponding case-patterns must include those labels; we should not feel required to force that burden on all other case-patterns purely to achieve consistency with this presumably-unusual style.</pre></blockquote><pre style="white-space:pre-wrap" class=""><blockquote type="cite" class="">Accordingly, while it needs to be possible to include associated value labels in a case-pattern, and in some situations it may be wise to include them, the core team believes that requiring associated value labels would be unduly onerous.</blockquote></pre><div class=""><br class=""></div></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">This sounds fine in principle, but I believe it is inconsistent with the goals of the proposal and doesn’t actually normalize much about the existing pattern matching process. As it stands, labels may be omitted from patterns because Swift’s philosophy before this proposal is that associated values in enum cases were conceptually tuples. With the addition of default arguments, the ability to overload case names with differing associated value labels, and making the labels part of the API name, there is no reason we should allow tuple-like behavior in just this one case.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><blockquote type="cite" class=""><pre style="white-space:pre-wrap" class="">While an associated-value label...</pre></blockquote><div class=""><br class=""></div></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">While it is true that a user often has a domain-specific intention for variables created during the destructuring process, the labels do not distract from the original purpose of the API and the user is still free to provide whatever name they see fit.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><blockquote type="cite" class=""><pre style="white-space:pre-wrap" class="">Therefore this risk is somewhat over-stated, and of course the programmer should remain free to include labels for cases where they feel the risk is significant...</pre></blockquote><div class=""><br class=""></div><div class="">This is phrased as a matter of choice, in practice this is perplexing. Recall an earlier rejected pattern:</div><div class=""><br class=""></div><div class=""><div style="font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><span style="color:rgb(186,45,162)" class="">enum</span> Foo {</div><div style="font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""> <span style="color:rgb(186,45,162)" class="">case</span> foo(x: Int, y: Int)</div><div style="font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class="">}</div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><span style="color:rgb(186,45,162)" class="">if</span><span style="" class=""> </span><span style="color:rgb(186,45,162)" class="">case</span><span style="" class=""> </span><span style="color:rgb(186,45,162)" class="">let</span><span style="" class=""> .foo(x, y: y) {} </span>// Bad! Missing label ‘x'</div></div><div style="color:rgb(0,132,0);font-family:Menlo;font-size:11px;margin:0px;line-height:normal" class=""><br class=""></div></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">From the user’s perspective, it is obvious what should happen: Either they did, or did not, intend to match labels. From the compiler’s perspective this is a proper ambiguity. Did the user intend to provide a “more meaningful name” and hence meant to elide the label, or did the user intend to match all the labels but forgot or deleted one? It is not obvious why, if we’re making the distinction, we should assume one way or the other. This case only gets worse when we must diagnose intent if the case is also overloaded by base name.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">I don’t see how it is "unduly onerous” to teach code completion to suggest the full name of an enum case everywhere or to create diagnostics that always insert missing labels in patterns to correct the user’s mistake. Freedom of choice is, in this case, only making a hard problem harder.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><blockquote type="cite" class=""><pre style="white-space:pre-wrap" class="">It is likely that cases will continue to be predominantly distinguished by their base name alone...</pre></blockquote><div class=""><br class=""></div><div class="">This makes sense given the current state of the world, but under this proposal we fully expect users to be overloading that base name and writing more and more ambiguous patterns. We should encourage disambiguating these cases with labels as a matter of both principle and QoI. </div></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">A pattern is meant to mirror the way a value was constructed with destructuring acting as a dual to creation. By maintaining the structure of the value in the pattern, labels included, users can properly convey that they intend the label to be a real part of the API of an enum case with associated values instead of just an ancillary storage area. Further, we can actually simplify pattern matching by making enum cases consistent with something function-like instead of tuple-like.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">To that end, I'd like the rationale and the proposal to be amended to require labels in patterns in all cases.</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">Thoughts?</div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class=""><br class=""></div><div style="font-family: Helvetica; font-size: 12px; margin: 0px; line-height: normal;" class="">~Robert Widmann</div><div class=""><br class=""></div></div></div></div></div></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" rel="noreferrer" target="_blank" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class="">
</blockquote></div>
_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></body></html>