> 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

Reply via email to