<div dir="ltr">On Sat, Apr 1, 2017 at 3:38 PM, Daniel Duan <span dir="ltr">&lt;<a href="mailto:daniel@duan.org" target="_blank">daniel@duan.org</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word">Thanks again for a detailed review. I have a few comments inline.<div><br><div><div><span class="gmail-"><blockquote type="cite"><div>On Apr 1, 2017, at 9:50 AM, Xiaodi Wu via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" target="_blank">swift-evolution@swift.org</a>&gt; wrote:</div><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div></div><div><span class="gmail-m_-6639013791274453729gmail-m_-1499090096552945119Apple-tab-span" style="white-space:pre-wrap">        </span>• Does this proposal fit well with the feel and direction of Swift?<br></div></div></div></div></blockquote><div><br></div><div>The &quot;Pattern consistency&quot; section does not align well with the feel and direction of Swift. Specifically, it does not explore some of the difficulties that arise from the proposed rules, adopts some of the same shortcomings that required revision for SE-0111, and deviates from some of the anticipated fixes for those shortcomings outlined in the core team&#39;s &quot;update and commentary&quot; to SE-0111.</div><div><br></div><div>It is not the case that the design proposed is &quot;a consequence of no longer relying on tuple patterns,&quot; in that it is not the inevitable result that falls out of that decision. </div></div></div></div></div></blockquote><div><br></div></span><div>The text in this revision may be poorly phrased. The connection, as I pointed out in an previous thread, is that we need to define syntax for enum pattern matching because the one we’ve been using in Swift 3 is tuple pattern’s syntax, which is now distinct and separate.</div></div></div></div></div></blockquote><div><br></div><div>What I&#39;m saying here is that, although _some_ change becomes necessary, the particular changes proposed here are not themselves &quot;a consequence of no longer relying on tuple patterns.&quot;</div><div><br></div><div>Put another way, given `enum E { case foo(bar: Int, baz: Int) }`, not being allowed to write `switch e { case foo(let a, let b): break }` is *not* an inevitable consequence of moving away from tuple patterns. Since the particular proposed changes break more existing source code than is strictly necessary for moving away from tuple-based pattern matching, those choices require stringent justification.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div>I will detail the alternative design that requires the fewest deviations or special rules, and breaks the least code extant today, later on. First, the shortcomings:</div><div><br></div><div><div>1.</div><div>The proposed rules for pattern matching are a source-breaking change, and are *not* the most minimal such change given the abandoning of tuples (see alternative below). However, the proposal does not engage with the core team&#39;s Swift 4 criteria for source-breaking changes with respect to the proposed &quot;stricter rules&quot; for pattern matching. There is no text at all about why specifically having the compiler encourage local _variable_ names to match argument labels resolves an active harm that outweighs the goal of preserving the greatest possible source compatibility.</div></div></div></div></div></div></blockquote><div><br></div></span><div>With this proposal, user can still use local variable names. It is true that if there are many ways to achieve the same thing, the compiler would be encouraging user to do that thing. But that puts a cost on the compiler, new users and experienced readers in unfamiliar codebases. This is (albeit not to a satisfactory degree, it seems) pointed out in the motivation section. </div><div><br></div><div>As for source compatibility, Swift 3 code should continue to work with warnings. Swift 4 mode would issue errors along with fix-its, which the migrator can leverage. Depends on core team/community’s implementor resource, there’s even a chance that this change would roll out one version later (warning in 4.X, error in 5.Y). In theory, the migration hurdle can be minimized.</div></div></div></div></div></blockquote><div><br></div><div>Many syntactic changes can be migrated in this way, but for Swift 4, that would only be justified when the existing syntax meets a high bar for being harmful. Again, the overarching theme of my response is that I don&#39;t think the proposed &quot;stricter rules&quot; offer much more harm mitigation than significantly less source-breaking designs for pattern matching, and I don&#39;t see anything in the proposal text that discusses the issue or justifies the particular design over less source-breaking alternatives.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><div><br></div><div>OTOH, the proposal does outline a major use case for a local variable name that does not match the argument label: `param` vs `parameter`. Widely-respected style guides in various languages encourage unabbreviated and descriptive API names but much more concise local variable names. This is a legitimate and good practice being actively discouraged by the sugared rules.</div></div></div></div></div></div></blockquote><div><br></div></span><div>This not a counterpoint, but I personally think using shortened names is not something to be encouraged. A (admittedly quirky) practice some of us inherited from the Cocoa style guideline is to use real, complete words for variable names. I’d like to think that The Swift API Design Guidelines are aligned in spirit on this matter - “clarity is more important than brevity”. (incidentally, the guidelines’s code samples don’t contain partial-word variables anywhere).</div></div></div></div></div></blockquote><div><br></div><div>We&#39;re talking _local_ variables: local variables aren&#39;t API. There are many, many examples of single-letter variables in the design guidelines. For example, `x = y.union(z)` has three of them.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><div><br></div><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><div><br></div><div>This would be merely annoying and not harmful if we could guarantee that it only means the API user will have to use longer local names, but the natural impulse on the part of thoughtful API authors would be to limit the expressiveness of their labels to help out their users.</div><div><br></div><div>This puts API authors in an impossible bind: they need to choose labels that are not too short lest it collide frequently with existing local variable names (`x` and `y` would be suboptimal, for example, but there are good reasons why an associated value might have arguments labeled `x` and `y`), </div></div></div></div></div></div></blockquote><div><br></div></span><div>API authors are already in this impossible bind: whenever they export a type name, a method signature in an open class or a protocol, risk of collision come up.</div></div></div></div></div></blockquote><div><br></div><div>Again, local variables aren&#39;t API. API authors have never been in this bind with respect to local variables. Nothing in the language has ever caused API to restrict the consumer&#39;s choice of local variable names. I think this is a highly, highly unusual rule.</div><div> </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><div>When a local variable does collide with a payload label, it would be bad if the user accidentally used the variable _in stead of_ the actual payload value. Forcing users to proactively rebind the variable would make them more mindful for this type of mistake.</div></div></div></div></div></blockquote><div><br></div><div>What mistake do you have in mind? Currently, labels have nothing to do with variable names. How does a user accidentally use a label name instead of a variable name?</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><br><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><div>but they also need to choose labels that are not too verbose. The safest bet in this case would be not to label at all, but then they lose the communicative aspect of argument labels (see point 2 below).</div></div></div></div></div></div></blockquote><div><br></div></span><div>A more realistic version of the story: API author choose labels that make the most sense for the declaration and user accept the risk of collision as they use the API. Most of those who choose to skip labels would not have given this much thought about their effect at all.</div><span class="gmail-"><div><br></div><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>2.</div><div>In the &quot;update and commentary&quot; revising SE-0111, it was acknowledged that &quot;cosmetic&quot; labels have a significant use case. Thus, the rules were changed to allow `(_ foo: Int, _ bar: Int) -&gt; ()` to communicate to the reader of code that the first argument serves some purpose &quot;foo&quot; without forcing that name to be part of the API, pending further revisions.<br></div><div><br></div><div>Because enum cases are currently tuples, labels can be dropped freely, and therefore these labels are effectively &quot;optional&quot; parts of the API that can be seen by the user but, at their discretion, not used. That fulfills the use case of &quot;cosmetic&quot; labels. In this revised proposal, by requiring the argument label to be actually _written_ somewhere by the API user, it puts a dent into the legitimate use case of &quot;cosmetic&quot; labels.</div><div><br></div><div>That is to say, an API author who wishes to communicate something about a parameter by using a label must now also consider if that label is also appropriate as a variable name and must forgo its use if the label is not so appropriate. This is a very different decision-making process and it is being applied retroactively to previously designed APIs whose labels would have been (hopefully thoughtfully) chosen under very different circumstances.</div></div></div></div></div></blockquote><div><br></div></span><div>This is something we never agreed on: SE-0111 is about functions. In some languages, patterns does resemble constructor functions, but that’s as much similarity as one can get anywhere. I still think applying every decision we made about functions to pattern matching is weird.</div></div></div></div></div></blockquote><div><br></div><div>I have to admit, I still don&#39;t understand your reticence. The first part of your proposal aligns enum cases with functions. If we are to look for patterns in something that is spelled like a function, then it is natural for the pattern itself to be spelled like a function, no? Currently, in Swift 3, since we&#39;re trying to use pattern matching for a tuple, the pattern is spelled like a tuple. In my simplistic mind, if we&#39;re trying to use pattern matching for a $foo, the pattern should be spelled like a $foo. Far from being weird, to me that is the only possible intuitive syntax.</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><div>But here’s my analysis anyways: the “cosmetic label” comment is about paving a way to restore expressivity of closures. It talks about the *interaction* between a function/closure’s declaration and use site — if parameter names are provided in a closure’s declaration, they should be required at invocation, similar to pre-SE-0111. IMO this proposal makes enum case and patterns closer to this goal.</div></div></div></div></div></blockquote><div><br></div><div>I agree that your proposal does indeed get us closer to SE-0111. By requiring argument labels chosen by the API author to be written out by the user, we get closer to the goals of SE-0111. But SE-0111 also had a large drawback that required post-approval modification, which was that there ended up being no way to write &quot;cosmetic labels,&quot; which both the community and core team agreed was an important use case.</div><div><br></div><div>With functions, that role can be filled with internal parameter names. This is what the &quot;update and commentary&quot; restored to SE-0111. With tuples, that role is filled by the labels themselves, because they can be ergonomically erased. With enum cases, you have not provided a parallel facility for cosmetic labels, because in your proposal labels can no longer be easily erased, but nor are there internal parameter names or some other substitute. I&#39;m saying that we should learn from the problems discovered after SE-0111 was approved and fix that shortcoming for enum cases before this proposal is adopted. </div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div>3.</div><div>The first part of the proposal aligns enum case syntax with functions. Functions often taken prepositions as argument labels, and indeed previous SE proposals have extended the rules to allow most words. However, `case foo(index: Int, in: T)` would have a disastrous label, as `in` would be a very annoying variable name whose use would be actively encouraged by the proposed sugared pattern matching rules.</div><div><br></div><div>The proposed rules for the sugared pattern would also require (well, greatly encourage) unique labels for each argument. This again is inconsistent with the naming conventions encouraged by the first part of the proposal aligning enum case syntax with functions, which have no such restrictions. If a user names something `case foo(point: T, point: T)`, then the matching rules would actively encourage an invalid redefinition of a variable named `point`.</div><div><br></div><div>(On the other hand, the API author does not have the luxury of naming the same case `foo(from point: T, to point: T)`, and even if they did, prepositions can make lousy local variable names--see first paragraph.)</div></div></div></div></div></blockquote><div><br></div></span>I don’t see this as a problem for enum case authors. It just means the poor pattern writer needs to provide the positional information to disambiguate.</div></div></div></div></blockquote><div><br></div><div> What do you mean by &quot;positional information&quot; here?</div><div><br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left-width:1px;border-left-style:solid;border-left-color:rgb(204,204,204);padding-left:1ex"><div style="word-wrap:break-word"><div><div><div><span class="gmail-"><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div>4.</div><div>The proposal does not explore what happens when the proposed prohibition on &quot;mixing and matching&quot; the proposed sugared and unsugared pattern matching runs up against associated values that have a mix of labeled and unlabeled parameters, and pattern matching user cases where the user does not wish to bind all of the arguments.</div><div><br></div><div>Given `case foo(a: Int, String, b: Int, String)`, the only sensible interpretation of the rules for sugared syntax would allow the user to choose any name for some but not all of the labels. If the user wishes to bind only `b`, however, he or she will need to navigate a puzzling set of rules that are not spelled out in the proposal:</div><div><br></div><div>```</div><div>case foo(a: _, _, b: let b, _)</div><div>// this is definitely allowed</div><div><br></div><div>case foo(a: _, _, b: let myVar, _)</div><div>// this is also definitely allowed</div><div><br></div><div>// but...</div><div><div>case foo(_, _, b: let myVar, _)</div><div>// is this allowed, or must the user explicitly state and not bind `a`?</div></div><div><br></div><div>// ...and with respect to the sugared version...</div><div>case foo(_, _, let b, _)</div><div>// is this allowed, or must the user explicitly state and not bind `a`?</div><div>```</div><div><br></div></div></div></div></div></blockquote><div><br></div></span><div>Good point. To make up for this: `_` can substitute any sub pattern, which is something that this proposal doesn’t change but definitely worth spelling out.  </div><span class="gmail-"><br><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div>5.</div><div>In the &quot;update and commentary&quot; revising SE-0111, the core team outlined a preferred path to restoring the full use of argument labels for functions without giving them type system significance. They gave a non-sugared form and a sugared form, both of which have met with approval from the community.</div><div><br></div><div>Briefly, the non-sugared form allows compound names to be used in variable names: `<span style="white-space:pre-wrap">func foo(opToUse op(lhs:rhs:) : (Int, Int) -&gt; Int)`. </span>The first part of this proposal is consistent in that it removes the type system significance of argument labels from the associated values of enum cases, and considers them as part of the enum case name. It also stands to reason that, if a user were to match a case _without_ trying to bind any variables, the same syntax would have be used if the base name is ambiguous: `case elet(locals:body:): break`.</div><div><br></div><div>However, the proposal makes no provision for using that same compound name in pattern matching. There appears to be no particular reason for its isolated omission here, as `case elet(locals:body:)(let a, let b): return a * b` is readable and presents no syntactic difficulties. (Moreover, it is consistent with the syntax permitted in this proposal for initializing a variable: `let foo = Expr.elet(locals:body:)([], anExpr)`.)</div></div></div></div></div></blockquote><div><br></div></span><div>Another good point. We can handle this in the purely additional proposal for compound variable names. I consider this not the 5th item in the list, but a separate suggestion, however :P</div><span class="gmail-"><br><blockquote type="cite"><div><div dir="ltr" style="font-family:helvetica;font-size:12px;font-style:normal;font-variant-caps:normal;font-weight:normal;letter-spacing:normal;text-align:start;text-indent:0px;text-transform:none;white-space:normal;word-spacing:0px"><div class="gmail_extra"><div class="gmail_quote"><div><br></div><div>--- </div><div><br></div><div>In light of these shortcomings, I would argue that the following alternative scheme is the most intuitive and consistent for pattern matching given the general agreement that enum case representation should be &quot;normalized&quot;:</div><div><br></div><div>Given:</div><div><br></div><div>```</div><div>enum S {</div><div>  case foo(bar: Int, baz: Int)</div><div>  case foo(boo: String)</div><div>  case bar(boo: String)</div><div>}</div><div>```</div><div><br></div><div>a. As in functions after SE-0111, enum cases can be identified unambiguously, regardless of whether one is initializing a variable or matching a case, by their compound name, e.g. `bar(boo:)`. Where a case can be unambiguously identified with only the base name, that is an alternative spelling, e.g. `bar`. Where a case cannot be identified uniquely with the base name, then it is an error to try to use the base name alone: `case foo: break // error: unambiguous`.</div><div><br></div><div>b. As in functions after SE-0111, arguments can be passed in either a sugared form or an unsugared form, and they can be bound in a pattern matching statement in the same way. That is, `case foo(bar: let a, baz: let b): break` and `case foo(bar:baz:)(let a, let b): break` are equivalent.</div><div><br></div><div>c. As in functions, one cannot supply different or incorrect argument labels. That is, `case foo(baz: let a, bar: let b)` and `case foo(baz:bar:)(let a, let b)` are both forbidden. _This recovers the vast majority of the additional syntactic safety that is outlined in the revised proposal, but without the use of any special rules for pattern matching._</div><div><br></div><div>d. By composing rules (a) and (b), `case bar(let a)` is allowed as it is today, preserving source compatibility. However `case foo(let b, let c)` is not allowed, and _not_ because different local variable names are chosen, but because the enum has two cases named foo.</div></div></div></div></div></blockquote><div><br></div></span>From a user’s point of view, there’s enough positional information in this pattern for the compiler to figure out which case it should match. This would be very unintuitive IMO.</div></div></div></div></blockquote><div><br></div><div>Wait, the key point of your proposal, with its &quot;stricter rules,&quot; is that labels shouldn&#39;t be optional even with sufficient positional information! That&#39;s also the whole thing above about getting us closer to aligning with SE-0111, etc.</div><div><br></div></div></div></div>