> On Sep 3, 2017, at 1:35 PM, Xiaodi Wu via swift-evolution > <[email protected]> wrote: > > 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. > > To start off, the premise, if I recall, going into review was that the author > **rejected** the notion that pattern matching should mirror creation.
Original author here. Here’s the review thread, for context: https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170306/thread.html#33626 <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170306/thread.html#33626> 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: https://github.com/apple/swift-evolution/blob/43ca098355762014f53e1b54e02d2f6a01253385/proposals/0155-normalize-enum-case-representation.md <https://github.com/apple/swift-evolution/blob/43ca098355762014f53e1b54e02d2f6a01253385/proposals/0155-normalize-enum-case-representation.md> The strictness of label requirements got progressively knocked down as the proposal graduated from 1st to 2nd revision to acceptance rationale 😅. > 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. > > 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. > > In any case, the conclusion reached is precedented in the world of functions: > > func g(a: Int, b: Int) { ... } > let f = g > f(1, 2) > > On Sun, Sep 3, 2017 at 15:13 Robert Widmann via swift-evolution > <[email protected] <mailto:[email protected]>> wrote: > Hello Swift Evolution, > > I took up the cause of implementing SE-0155 > <https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md>, > and am most of the way through the larger points of the proposal. One thing > struck me when I got to the part about normalizing the behavior of pattern > matching > <https://github.com/apple/swift-evolution/blob/master/proposals/0155-normalize-enum-case-representation.md#pattern-consistency>. > The Core Team indicated in their rationale > <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170417/035972.html> > that the proposal’s suggestion that a variable binding sub in for a label > was a little much as in this example: > > enum Foo { > case foo(x: Int, y: Int) > } > if case let .foo(x: x, y: y) {} // Fine! Labels match and are in order > if case let .foo(x, y: y) {} // Bad! Missing label 'x' > if case let .foo(x, y) {} // Fine? Missing labels, but variable names match > labels > > They instead suggested the following behavior: > > enum Foo { > case foo(x: Int, y: Int) > } > if case let .foo(x: x, y: y) {} // Fine! Labels match and are in order > if case let .foo(x, y: y) {} // Bad! Missing label 'x' > if case let .foo(x, y) {} // Fine? Missing labels, and full name of case is > unambiguous > > Which, for example, would reject this: > > enum Foo { > case foo(x: Int, y: Int) // Note: foo(x:y:) > case foo(x: Int, z: Int) // Note: foo(x:z:) > } > if case let .foo(x, y) {} // Bad! Are we matching foo(x:y:) or foo(x:z:)? > > With this reasoning: > >> - 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. >> 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. > > > 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. > >> While an associated-value label... > > 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. > >> 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... > > This is phrased as a matter of choice, in practice this is perplexing. > Recall an earlier rejected pattern: > > enum Foo { > case foo(x: Int, y: Int) > } > if case let .foo(x, y: y) {} // Bad! Missing label ‘x' > > 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. > > 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. > >> It is likely that cases will continue to be predominantly distinguished by >> their base name alone... > > 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. > > 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. > > To that end, I'd like the rationale and the proposal to be amended to require > labels in patterns in all cases. > > Thoughts? > > ~Robert Widmann > > _______________________________________________ > swift-evolution mailing list > [email protected] <mailto:[email protected]> > https://lists.swift.org/mailman/listinfo/swift-evolution > <https://lists.swift.org/mailman/listinfo/swift-evolution> > _______________________________________________ > swift-evolution mailing list > [email protected] > https://lists.swift.org/mailman/listinfo/swift-evolution
_______________________________________________ swift-evolution mailing list [email protected] https://lists.swift.org/mailman/listinfo/swift-evolution
