Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 4:26 PM, Robert Widmann  wrote:
> 
>> 
>> On Sep 8, 2017, at 2:59 PM, Matthew Johnson > > wrote:
>> 
>>> 
>>> On Sep 8, 2017, at 2:17 PM, Robert Widmann >> > wrote:
>>> 
 
 On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
 > wrote:
 
 
> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan  > wrote:
> 
> I wasn't arguing for a strictly parallel syntax. I was arguing against 
> being able to omit labels. I don't view those as strictly tied together. 
> How are they?
 
 Like Xiaodi I don’t think it would be productive to rehash the prior 
 discussion so I’m going to try to be brief.  
 
 In the discussion one idea that arose was to support two labels for 
 associated values in a manner similar to parameters.  One would be used 
 during construction and the other during matching.  
 
 The idea behind this was that when creating a value a case is analagous to 
 a factory method and it would be nice to be able provide labels using the 
 same naming guidelines we use for external argument labels.  For example, 
 if an associated value was an index `at` might be used for clarity at the 
 call site.  Labels like this don’t necessarily make as much sense when 
 destructuring the value.  The idea of the “internal” label of a case was 
 that it would be used when matching and could be elided if the bound name 
 was identical.  In the example, `index` might be used.
>>> 
>>> It’s an interesting idea, but I don’t know of too many cases where I 
>>> wouldn’t want the name for destructuring to serve as an API name somehow.  
>>> A function may use labels to aid understanding, flow,  readability, etc. 
>>> but an enum case is not necessarily a function-like value, nor does this 
>>> proposal want them to be (modulo some internal modeling).
>> 
>> An enum case is *exactly* analogous to a static factory method or property 
>> when it is used to construct values.  It obviously plays a different role in 
>> pattern context.
>> 
>>> 
 
 When matching, `let` is interspersed between the label and the name 
 binding.
>>> 
>>> Good thing this works then
>>> 
>>> enum Foo {
>>>   case foo(x: Int, y: String, z: Float)
>>> }
>>> 
>>> func bar(_ x : Foo) {
>>>   switch x {
>>>   case let .foo(x: x, y: y, z: z): break
>>>   }
>>> }
>> 
>> I consider this syntax to be an anti-pattern.  It can be unclear where a new 
>> name is bound and where the value of a pre-existing name is matched.
>> 
>>> 
>>> Even better, John mentioned in the rationale that if the labels ever grow 
>>> to be clumsy we can come up with some kind of “ellipses-like” pattern to 
>>> indicate we intend to match all the labelled values as they are so named, 
>>> etc.  
>> 
>> It sounds like this would introduce name bindings without the name being 
>> explicitly declared.  That works fine where there is a standard pattern such 
>> as `oldValue` in a property observer.  I’m not sure I would like it in this 
>> context though.
>> 
>>> Or, and this is the far easier thing that can and should be done today, 
>>> just use a struct.
>> 
>> I generally agree with this advice.
>> 
>>> 
  Any label is already at a distance from the name it labels.  Instead of 
 providing a label the important thing is that the semantic of the bound 
 variable be clear at the match site.  Much of the time the label actually 
 reduces clarity at a match site by adding verbosity and very often 
 repetition.  If the bound name clearly communicates the purpose of the 
 associated value a label cannot add any additional clarity, it can only 
 reduce clarity.
>>> 
>>> I disagree.  This would make sense in a world where we didn’t allow 
>>> overloading.  But for the purpose of disambiguation, this kind of logic 
>>> breaks down.  Say we have this construction
>>> 
>>> func bar(_ x : Foo) {
>>>   switch x {
>>>   case let .foo(x, y, z): break
>>>   case let .foo(x, y, z, w): break
>>>   }
>>> }
>>> 
>>> Without the definition of the original enum, could you tell me what each of 
>>> these cases were for, and why they were named so similarly?  Eliding the 
>>> label does not enable clarity, it saves keystrokes and enables ambiguous 
>>> patterns.
>> 
>> As stated above, I strongly dislike the syntax that distributes the `let` as 
>> I find *that* to be unclear.  Let’s rewrite that example:
>> 
>> func bar(_ x : Foo) {
>>   switch x {
>>   case .foo(let x, let y, let z): break
>>   case .foo(let x, let y, let z, let w): break
>>   }
>> }
>> 
>> Now I can see exactly where names are being bound.  I know if a label exists 
>> it matches the name that is bound.  If two distinct 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Robert Widmann via swift-evolution

> On Sep 8, 2017, at 2:59 PM, Matthew Johnson  wrote:
> 
>> 
>> On Sep 8, 2017, at 2:17 PM, Robert Widmann > > wrote:
>> 
>>> 
>>> On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
>>> > wrote:
>>> 
>>> 
 On Sep 4, 2017, at 11:47 AM, T.J. Usiyan > wrote:
 
 I wasn't arguing for a strictly parallel syntax. I was arguing against 
 being able to omit labels. I don't view those as strictly tied together. 
 How are they?
>>> 
>>> Like Xiaodi I don’t think it would be productive to rehash the prior 
>>> discussion so I’m going to try to be brief.  
>>> 
>>> In the discussion one idea that arose was to support two labels for 
>>> associated values in a manner similar to parameters.  One would be used 
>>> during construction and the other during matching.  
>>> 
>>> The idea behind this was that when creating a value a case is analagous to 
>>> a factory method and it would be nice to be able provide labels using the 
>>> same naming guidelines we use for external argument labels.  For example, 
>>> if an associated value was an index `at` might be used for clarity at the 
>>> call site.  Labels like this don’t necessarily make as much sense when 
>>> destructuring the value.  The idea of the “internal” label of a case was 
>>> that it would be used when matching and could be elided if the bound name 
>>> was identical.  In the example, `index` might be used.
>> 
>> It’s an interesting idea, but I don’t know of too many cases where I 
>> wouldn’t want the name for destructuring to serve as an API name somehow.  A 
>> function may use labels to aid understanding, flow,  readability, etc. but 
>> an enum case is not necessarily a function-like value, nor does this 
>> proposal want them to be (modulo some internal modeling).
> 
> An enum case is *exactly* analogous to a static factory method or property 
> when it is used to construct values.  It obviously plays a different role in 
> pattern context.
> 
>> 
>>> 
>>> When matching, `let` is interspersed between the label and the name binding.
>> 
>> Good thing this works then
>> 
>> enum Foo {
>>   case foo(x: Int, y: String, z: Float)
>> }
>> 
>> func bar(_ x : Foo) {
>>   switch x {
>>   case let .foo(x: x, y: y, z: z): break
>>   }
>> }
> 
> I consider this syntax to be an anti-pattern.  It can be unclear where a new 
> name is bound and where the value of a pre-existing name is matched.
> 
>> 
>> Even better, John mentioned in the rationale that if the labels ever grow to 
>> be clumsy we can come up with some kind of “ellipses-like” pattern to 
>> indicate we intend to match all the labelled values as they are so named, 
>> etc.  
> 
> It sounds like this would introduce name bindings without the name being 
> explicitly declared.  That works fine where there is a standard pattern such 
> as `oldValue` in a property observer.  I’m not sure I would like it in this 
> context though.
> 
>> Or, and this is the far easier thing that can and should be done today, just 
>> use a struct.
> 
> I generally agree with this advice.
> 
>> 
>>>  Any label is already at a distance from the name it labels.  Instead of 
>>> providing a label the important thing is that the semantic of the bound 
>>> variable be clear at the match site.  Much of the time the label actually 
>>> reduces clarity at a match site by adding verbosity and very often 
>>> repetition.  If the bound name clearly communicates the purpose of the 
>>> associated value a label cannot add any additional clarity, it can only 
>>> reduce clarity.
>> 
>> I disagree.  This would make sense in a world where we didn’t allow 
>> overloading.  But for the purpose of disambiguation, this kind of logic 
>> breaks down.  Say we have this construction
>> 
>> func bar(_ x : Foo) {
>>   switch x {
>>   case let .foo(x, y, z): break
>>   case let .foo(x, y, z, w): break
>>   }
>> }
>> 
>> Without the definition of the original enum, could you tell me what each of 
>> these cases were for, and why they were named so similarly?  Eliding the 
>> label does not enable clarity, it saves keystrokes and enables ambiguous 
>> patterns.
> 
> As stated above, I strongly dislike the syntax that distributes the `let` as 
> I find *that* to be unclear.  Let’s rewrite that example:
> 
> func bar(_ x : Foo) {
>   switch x {
>   case .foo(let x, let y, let z): break
>   case .foo(let x, let y, let z, let w): break
>   }
> }
> 
> Now I can see exactly where names are being bound.  I know if a label exists 
> it matches the name that is bound.  If two distinct cases might be matched I 
> would expect a compiler error.  For example, if Foo was defined as follows 
> the above switch to produce an error on the second pattern but not the first:
> 
> enum Foo {
>   case foo(x: Int, y: String, z: Float)
>   

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Matthew Johnson via swift-evolution

> On Sep 8, 2017, at 2:17 PM, Robert Widmann  wrote:
> 
>> 
>> On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
>> > wrote:
>> 
>> 
>>> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan >> > wrote:
>>> 
>>> I wasn't arguing for a strictly parallel syntax. I was arguing against 
>>> being able to omit labels. I don't view those as strictly tied together. 
>>> How are they?
>> 
>> Like Xiaodi I don’t think it would be productive to rehash the prior 
>> discussion so I’m going to try to be brief.  
>> 
>> In the discussion one idea that arose was to support two labels for 
>> associated values in a manner similar to parameters.  One would be used 
>> during construction and the other during matching.  
>> 
>> The idea behind this was that when creating a value a case is analagous to a 
>> factory method and it would be nice to be able provide labels using the same 
>> naming guidelines we use for external argument labels.  For example, if an 
>> associated value was an index `at` might be used for clarity at the call 
>> site.  Labels like this don’t necessarily make as much sense when 
>> destructuring the value.  The idea of the “internal” label of a case was 
>> that it would be used when matching and could be elided if the bound name 
>> was identical.  In the example, `index` might be used.
> 
> It’s an interesting idea, but I don’t know of too many cases where I wouldn’t 
> want the name for destructuring to serve as an API name somehow.  A function 
> may use labels to aid understanding, flow,  readability, etc. but an enum 
> case is not necessarily a function-like value, nor does this proposal want 
> them to be (modulo some internal modeling).

An enum case is *exactly* analogous to a static factory method or property when 
it is used to construct values.  It obviously plays a different role in pattern 
context.

> 
>> 
>> When matching, `let` is interspersed between the label and the name binding.
> 
> Good thing this works then
> 
> enum Foo {
>   case foo(x: Int, y: String, z: Float)
> }
> 
> func bar(_ x : Foo) {
>   switch x {
>   case let .foo(x: x, y: y, z: z): break
>   }
> }

I consider this syntax to be an anti-pattern.  It can be unclear where a new 
name is bound and where the value of a pre-existing name is matched.

> 
> Even better, John mentioned in the rationale that if the labels ever grow to 
> be clumsy we can come up with some kind of “ellipses-like” pattern to 
> indicate we intend to match all the labelled values as they are so named, 
> etc.  

It sounds like this would introduce name bindings without the name being 
explicitly declared.  That works fine where there is a standard pattern such as 
`oldValue` in a property observer.  I’m not sure I would like it in this 
context though.

> Or, and this is the far easier thing that can and should be done today, just 
> use a struct.

I generally agree with this advice.

> 
>>  Any label is already at a distance from the name it labels.  Instead of 
>> providing a label the important thing is that the semantic of the bound 
>> variable be clear at the match site.  Much of the time the label actually 
>> reduces clarity at a match site by adding verbosity and very often 
>> repetition.  If the bound name clearly communicates the purpose of the 
>> associated value a label cannot add any additional clarity, it can only 
>> reduce clarity.
> 
> I disagree.  This would make sense in a world where we didn’t allow 
> overloading.  But for the purpose of disambiguation, this kind of logic 
> breaks down.  Say we have this construction
> 
> func bar(_ x : Foo) {
>   switch x {
>   case let .foo(x, y, z): break
>   case let .foo(x, y, z, w): break
>   }
> }
> 
> Without the definition of the original enum, could you tell me what each of 
> these cases were for, and why they were named so similarly?  Eliding the 
> label does not enable clarity, it saves keystrokes and enables ambiguous 
> patterns.

As stated above, I strongly dislike the syntax that distributes the `let` as I 
find *that* to be unclear.  Let’s rewrite that example:

func bar(_ x : Foo) {
  switch x {
  case .foo(let x, let y, let z): break
  case .foo(let x, let y, let z, let w): break
  }
}

Now I can see exactly where names are being bound.  I know if a label exists it 
matches the name that is bound.  If two distinct cases might be matched I would 
expect a compiler error.  For example, if Foo was defined as follows the above 
switch to produce an error on the second pattern but not the first:

enum Foo {
  case foo(x: Int, y: String, z: Float)
  case foo(x: Int, y: String, z: Float, s: String)
  case foo(x: Int, y: String, z: Float, w: Double)
}

If the proposal had been accepted without the modification I would not find the 
above switch ambiguous in behavior although I admit that it carries more 
potential for mistake 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Robert Widmann via swift-evolution

> On Sep 4, 2017, at 11:35 AM, Matthew Johnson via swift-evolution 
>  wrote:
> 
> 
>> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan > > wrote:
>> 
>> I wasn't arguing for a strictly parallel syntax. I was arguing against being 
>> able to omit labels. I don't view those as strictly tied together. How are 
>> they?
> 
> Like Xiaodi I don’t think it would be productive to rehash the prior 
> discussion so I’m going to try to be brief.  
> 
> In the discussion one idea that arose was to support two labels for 
> associated values in a manner similar to parameters.  One would be used 
> during construction and the other during matching.  
> 
> The idea behind this was that when creating a value a case is analagous to a 
> factory method and it would be nice to be able provide labels using the same 
> naming guidelines we use for external argument labels.  For example, if an 
> associated value was an index `at` might be used for clarity at the call 
> site.  Labels like this don’t necessarily make as much sense when 
> destructuring the value.  The idea of the “internal” label of a case was that 
> it would be used when matching and could be elided if the bound name was 
> identical.  In the example, `index` might be used.

It’s an interesting idea, but I don’t know of too many cases where I wouldn’t 
want the name for destructuring to serve as an API name somehow.  A function 
may use labels to aid understanding, flow,  readability, etc. but an enum case 
is not necessarily a function-like value, nor does this proposal want them to 
be (modulo some internal modeling).

> 
> When matching, `let` is interspersed between the label and the name binding.

Good thing this works then

enum Foo {
  case foo(x: Int, y: String, z: Float)
}

func bar(_ x : Foo) {
  switch x {
  case let .foo(x: x, y: y, z: z): break
  }
}

Even better, John mentioned in the rationale that if the labels ever grow to be 
clumsy we can come up with some kind of “ellipses-like” pattern to indicate we 
intend to match all the labelled values as they are so named, etc.  Or, and 
this is the far easier thing that can and should be done today, just use a 
struct.

>  Any label is already at a distance from the name it labels.  Instead of 
> providing a label the important thing is that the semantic of the bound 
> variable be clear at the match site.  Much of the time the label actually 
> reduces clarity at a match site by adding verbosity and very often 
> repetition.  If the bound name clearly communicates the purpose of the 
> associated value a label cannot add any additional clarity, it can only 
> reduce clarity.

I disagree.  This would make sense in a world where we didn’t allow 
overloading.  But for the purpose of disambiguation, this kind of logic breaks 
down.  Say we have this construction

func bar(_ x : Foo) {
  switch x {
  case let .foo(x, y, z): break
  case let .foo(x, y, z, w): break
  }
}

Without the definition of the original enum, could you tell me what each of 
these cases were for, and why they were named so similarly?  Eliding the label 
does not enable clarity, it saves keystrokes and enables ambiguous patterns.

> 
> The proposal acknowledges most of this by allowing us to elide labels when 
> the bound name matches the label. 

That part of the proposal was not accepted which is part of why I’m bringing 
this up at all.  Besides, it wouldn’t have worked quite the way the authors 
intended.

enum Foo {
  case foo(x: Int, x: String)
}

func bar(_ x : Foo) {
  switch x {
  // We wanted to avoid labels, but instead we would be required to redeclare
  // 'x' in this pattern which forces the use of labels to allow a different 
bound name.
  case let .foo(x, x): break
 }
}  

~Robert Widmann

> 
>> 
>> On Mon, Sep 4, 2017 at 12:38 PM, Matthew Johnson > > wrote:
>> 
>>> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution 
>>> > wrote:
>>> 
>>> While re-litigating has it's issues, I am for simplifying the rule and 
>>> always requiring the labels if they exist. This is similar to the change 
>>> around external labels. Yes, it is slightly less convenient, but it removes 
>>> a difficult to motivate caveat for beginners.
>> 
>> I disagree.  Creating a value and destructuring it are two very different 
>> operations and I believe it is a mistake to require them to have parallel 
>> syntax.  
>> 
>> Imagine a future enhancement to the language that supports destructuring a 
>> struct.  A struct might not have a strictly memberwise initializer.  It 
>> might not even be possible to reconstruct initializer arguments for the sake 
>> of parallel destructuring syntax.  There might even be more than one 
>> projection that is reasonable to use when destructuring the value in a 
>> pattern (such as cartesian and polar 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-08 Thread Robert Widmann via swift-evolution

> On Sep 4, 2017, at 4:05 PM, Christopher Kornher via swift-evolution 
>  wrote:
> 
> Apologies for rehashing this, but we seem to be going down that path… I am in 
> the minority on this issue and have held my opinions because I thought that 
> they would have served as simply a distraction and I was extremely busy at 
> the time. That may have been a mistake on my part, because raising these 
> issues now is after the fact.
> 
> I am airing them now for two reasons:
> 1) To ensure that at least the agreed upon compromise is implemented.
> 2) To hopefully improve the evolution process, and help ensure that similar 
> proposals are given the scrutiny that they deserve.
> 
> I have noticed a pattern in software and other projects over the years. The 
> most catastrophic failures and expensive rework has been due to flawed or at 
> least incomplete basic assumptions. New postulates / basic assumptions should 
> be subjected to rigorous scrutiny. I don’t think that they were in this case.
> 
> I am speaking up now because there is a proposal out there to follow what I 
> consider to be a flawed basic assumption to its logical conclusion, which 
> seems quite reasonable, if you accept the basic assumption, which I don’t, of 
> course. 
> 
> Please don’t take this as a personal attack on those on the other side. This 
> is a philosophical disagreement with no “right” and “wrong” answer. I don’t 
> believe that this proposal is terrible. In fact, the agreed-upon compromise 
> does improve the construction and matching of enum values and leaves only 
> edge cases that I hope to address in a future proposal — specifically 
> matching is made more difficult in some cases of name overloading. 
> 
> The history of the process as I saw it:
>   There was a widely perceived problem with enums involving what could be 
> described as “legacy destructuring” which could lead to confusing code and 
> hard to discover transposition errors.
> 
>   A solution was proposed that was based upon an overarching premise: 
> that enums should be modeled as much as possible after function calls to 
> simplify the language. This led to the original proposal always requiring 
> labels (as function calls do, and closures don’t, but that is a discussion 
> for another time).
> 
> I believe that idea of using function calls as the primary model for enums is 
> flawed at its core. The problem is that enums and function calls only 
> resemble each other in Swift because some enums can have associated values. 

If the idea of modeling them as a tag and a tuple were OK, this proposal would 
not exist in the first place - or would be dramatically reduced in scope to 
just redoing pattern matching.  We are remodeling them as function-like 
precisely because the old scheme was causing headaches.  I feel it is 
reductionistic to say it is "only the case” that this is true given these 
circumstances.

> 
> The purpose of enums is to be matched. Enums that are never matched in some 
> way have no purpose. Function calls must always be “matched” (resolved) 
> unambiguously so that proper code can be executed. No such requirement exists 
> for enums. In fact the language includes rich functionality for matching 
> multiple cases and values with a single “case” (predicate). This is not a 
> flaw, it improves the expressive power of the language by allowing complex 
> matching logic to be expressed tersely and clearly.
> 

What complex matching (did you mean Expressive?) logic?  That you can express 
pattern matches just by matching by base name then a tuple pattern of proper 
cardinality with disjointed labels is far more complex and prone to actual 
ambiguities (the rationale and proposal both use some form of the phase “when a 
pattern is unambiguous”).  What this means in practice is that the scheme laid 
out in the proposal is prone to ambiguity by construction.  This does not 
enable expressive pattern matches, this enables users to save typing while 
simultaneously increasing the mental overhead of reading any switch statement.  
Under this proposal it is now impossible to tell at a glance which pattern over 
an Enum with overloaded base names is being matched unless you have the labels 
present.

> So, since the purpose of enums is to be matched, any modification to this 
> accepted proposal that makes that more difficult or cluttered should be 
> rejected.

I agree with the sentiment that we don’t want to increase entropy, but I 
disagree with the logic underpinning it.  You save a few keystrokes with this 
mentality.  You don’t gain anything in return.

~Robert Widmann

> 
> 
>> On Sep 4, 2017, at 9:52 AM, T.J. Usiyan via swift-evolution 
>> > wrote:
>> 
>> While re-litigating has it's issues, I am for simplifying the rule and 
>> always requiring the labels if they exist. This is similar to the change 
>> around external labels. Yes, it is 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-05 Thread Matthew Johnson via swift-evolution

> On Sep 5, 2017, at 3:07 AM, gs. via swift-evolution 
>  wrote:
> 
> 
> This becomes false in exactly the situation that you described where there 
> are two projections with similar structure, no? Labels would remove ambiguity 
> here. 
> TJ 

That depends on what names are bound.  If the bound names clearly indicate 
which projection is matched that is not the case.  Further, the projections 
themselves would probable have a different base name which was used in the 
pattern.

> 
>> On Sep 4, 2017, at 19:35, Matthew Johnson  wrote:
>> 
>> If the bound name clearly communicates the purpose of the associated value a 
>> label cannot add any additional clarity, it can only reduce clarity
> ___
> swift-evolution mailing list
> swift-evolution@swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-05 Thread gs. via swift-evolution

This becomes false in exactly the situation that you described where there are 
two projections with similar structure, no? Labels would remove ambiguity here. 
TJ 

> On Sep 4, 2017, at 19:35, Matthew Johnson  wrote:
> 
> If the bound name clearly communicates the purpose of the associated value a 
> label cannot add any additional clarity, it can only reduce clarity
___
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution


Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Christopher Kornher via swift-evolution
Apologies for rehashing this, but we seem to be going down that path… I am in 
the minority on this issue and have held my opinions because I thought that 
they would have served as simply a distraction and I was extremely busy at the 
time. That may have been a mistake on my part, because raising these issues now 
is after the fact.

I am airing them now for two reasons:
1) To ensure that at least the agreed upon compromise is implemented.
2) To hopefully improve the evolution process, and help ensure that similar 
proposals are given the scrutiny that they deserve.

I have noticed a pattern in software and other projects over the years. The 
most catastrophic failures and expensive rework has been due to flawed or at 
least incomplete basic assumptions. New postulates / basic assumptions should 
be subjected to rigorous scrutiny. I don’t think that they were in this case.

I am speaking up now because there is a proposal out there to follow what I 
consider to be a flawed basic assumption to its logical conclusion, which seems 
quite reasonable, if you accept the basic assumption, which I don’t, of course. 

Please don’t take this as a personal attack on those on the other side. This is 
a philosophical disagreement with no “right” and “wrong” answer. I don’t 
believe that this proposal is terrible. In fact, the agreed-upon compromise 
does improve the construction and matching of enum values and leaves only edge 
cases that I hope to address in a future proposal — specifically matching is 
made more difficult in some cases of name overloading. 

The history of the process as I saw it:
There was a widely perceived problem with enums involving what could be 
described as “legacy destructuring” which could lead to confusing code and hard 
to discover transposition errors.

A solution was proposed that was based upon an overarching premise: 
that enums should be modeled as much as possible after function calls to 
simplify the language. This led to the original proposal always requiring 
labels (as function calls do, and closures don’t, but that is a discussion for 
another time).

I believe that idea of using function calls as the primary model for enums is 
flawed at its core. The problem is that enums and function calls only resemble 
each other in Swift because some enums can have associated values. 

The purpose of enums is to be matched. Enums that are never matched in some way 
have no purpose. Function calls must always be “matched” (resolved) 
unambiguously so that proper code can be executed. No such requirement exists 
for enums. In fact the language includes rich functionality for matching 
multiple cases and values with a single “case” (predicate). This is not a flaw, 
it improves the expressive power of the language by allowing complex matching 
logic to be expressed tersely and clearly.

So, since the purpose of enums is to be matched, any modification to this 
accepted proposal that makes that more difficult or cluttered should be 
rejected.


> On Sep 4, 2017, at 9:52 AM, T.J. Usiyan via swift-evolution 
>  wrote:
> 
> While re-litigating has it's issues, I am for simplifying the rule and always 
> requiring the labels if they exist. This is similar to the change around 
> external labels. Yes, it is slightly less convenient, but it removes a 
> difficult to motivate caveat for beginners.
> 
> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution 
> > 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. 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 
> > wrote:
> Hello Swift Evolution,
> 
> I took up the cause of implementing SE-0155 
> 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Daniel Duan via swift-evolution

> On Sep 3, 2017, at 1:35 PM, Xiaodi Wu via swift-evolution 
>  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
 


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
 


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 
> > wrote:
> Hello Swift Evolution,
> 
> I took up the cause of implementing SE-0155 
> ,
>  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 
> .
>   The Core Team indicated in their rationale 
> 
>  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 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Matthew Johnson via swift-evolution

> On Sep 4, 2017, at 11:47 AM, T.J. Usiyan  wrote:
> 
> I wasn't arguing for a strictly parallel syntax. I was arguing against being 
> able to omit labels. I don't view those as strictly tied together. How are 
> they?

Like Xiaodi I don’t think it would be productive to rehash the prior discussion 
so I’m going to try to be brief.  

In the discussion one idea that arose was to support two labels for associated 
values in a manner similar to parameters.  One would be used during 
construction and the other during matching.  

The idea behind this was that when creating a value a case is analagous to a 
factory method and it would be nice to be able provide labels using the same 
naming guidelines we use for external argument labels.  For example, if an 
associated value was an index `at` might be used for clarity at the call site.  
Labels like this don’t necessarily make as much sense when destructuring the 
value.  The idea of the “internal” label of a case was that it would be used 
when matching and could be elided if the bound name was identical.  In the 
example, `index` might be used.

When matching, `let` is interspersed between the label and the name binding.  
Any label is already at a distance from the name it labels.  Instead of 
providing a label the important thing is that the semantic of the bound 
variable be clear at the match site.  Much of the time the label actually 
reduces clarity at a match site by adding verbosity and very often repetition.  
If the bound name clearly communicates the purpose of the associated value a 
label cannot add any additional clarity, it can only reduce clarity.

The proposal acknowledges most of this by allowing us to elide labels when the 
bound name matches the label.  It doesn’t allow for a distinction between the 
call-site label used when creating a value from the match-site name that allows 
elision.  My recollection of the discussion leads me to believe that is 
unlikely to ever be accepted as an enhancement.  That said, nothing in the 
current design strictly prevents us from considering that in the future if 
experience demonstrates that it would be useful.

> 
> On Mon, Sep 4, 2017 at 12:38 PM, Matthew Johnson  > wrote:
> 
>> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution 
>> > wrote:
>> 
>> While re-litigating has it's issues, I am for simplifying the rule and 
>> always requiring the labels if they exist. This is similar to the change 
>> around external labels. Yes, it is slightly less convenient, but it removes 
>> a difficult to motivate caveat for beginners.
> 
> I disagree.  Creating a value and destructuring it are two very different 
> operations and I believe it is a mistake to require them to have parallel 
> syntax.  
> 
> Imagine a future enhancement to the language that supports destructuring a 
> struct.  A struct might not have a strictly memberwise initializer.  It might 
> not even be possible to reconstruct initializer arguments for the sake of 
> parallel destructuring syntax.  There might even be more than one projection 
> that is reasonable to use when destructuring the value in a pattern (such as 
> cartesian and polar coordinates).
> 
> FWIW, I made this case in more detail during the discussion and review of 
> this proposal.
> 
>> 
>> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution 
>> > 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. 
>> 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 
>> > wrote:
>> Hello Swift Evolution,
>> 
>> I took up the cause of implementing SE-0155 
>> 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread T.J. Usiyan via swift-evolution
I wasn't arguing for a strictly parallel syntax. I was arguing against
being able to omit labels. I don't view those as strictly tied together.
How are they?

On Mon, Sep 4, 2017 at 12:38 PM, Matthew Johnson 
wrote:

>
> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution <
> swift-evolution@swift.org> wrote:
>
> While re-litigating has it's issues, I am for simplifying the rule and
> always requiring the labels if they exist. This is similar to the change
> around external labels. Yes, it is slightly less convenient, but it removes
> a difficult to motivate caveat for beginners.
>
>
> I disagree.  Creating a value and destructuring it are two very different
> operations and I believe it is a mistake to require them to have parallel
> syntax.
>
> Imagine a future enhancement to the language that supports destructuring a
> struct.  A struct might not have a strictly memberwise initializer.  It
> might not even be possible to reconstruct initializer arguments for the
> sake of parallel destructuring syntax.  There might even be more than one
> projection that is reasonable to use when destructuring the value in a
> pattern (such as cartesian and polar coordinates).
>
> FWIW, I made this case in more detail during the discussion and review of
> this proposal.
>
>
> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution <
> swift-evolution@swift.org> 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. 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 <
>> swift-evolution@swift.org> wrote:
>>
>>> Hello Swift Evolution,
>>>
>>> I took up the cause of implementing SE-0155
>>> ,
>>> 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
>>> .
>>> The Core Team indicated in their rationale
>>> 
>>>  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 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread Matthew Johnson via swift-evolution

> On Sep 4, 2017, at 10:52 AM, T.J. Usiyan via swift-evolution 
>  wrote:
> 
> While re-litigating has it's issues, I am for simplifying the rule and always 
> requiring the labels if they exist. This is similar to the change around 
> external labels. Yes, it is slightly less convenient, but it removes a 
> difficult to motivate caveat for beginners.

I disagree.  Creating a value and destructuring it are two very different 
operations and I believe it is a mistake to require them to have parallel 
syntax.  

Imagine a future enhancement to the language that supports destructuring a 
struct.  A struct might not have a strictly memberwise initializer.  It might 
not even be possible to reconstruct initializer arguments for the sake of 
parallel destructuring syntax.  There might even be more than one projection 
that is reasonable to use when destructuring the value in a pattern (such as 
cartesian and polar coordinates).

FWIW, I made this case in more detail during the discussion and review of this 
proposal.

> 
> On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution 
> > 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. 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 
> > wrote:
> Hello Swift Evolution,
> 
> I took up the cause of implementing SE-0155 
> ,
>  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 
> .
>   The Core Team indicated in their rationale 
> 
>  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 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-04 Thread T.J. Usiyan via swift-evolution
While re-litigating has it's issues, I am for simplifying the rule and
always requiring the labels if they exist. This is similar to the change
around external labels. Yes, it is slightly less convenient, but it removes
a difficult to motivate caveat for beginners.

On Sun, Sep 3, 2017 at 4:35 PM, Xiaodi Wu via swift-evolution <
swift-evolution@swift.org> 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. 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 <
> swift-evolution@swift.org> wrote:
>
>> Hello Swift Evolution,
>>
>> I took up the cause of implementing SE-0155
>> ,
>> 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
>> .
>> The Core Team indicated in their rationale
>> 
>>  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 

Re: [swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-03 Thread Xiaodi Wu via swift-evolution
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. 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 <
swift-evolution@swift.org> wrote:

> Hello Swift Evolution,
>
> I took up the cause of implementing SE-0155
> ,
> 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
> .
> The Core Team indicated in their rationale
> 
>  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
> 

[swift-evolution] [SE-0155][Discuss] The role of labels in enum case patterns

2017-09-03 Thread Robert Widmann via swift-evolution
Hello Swift Evolution,

I took up the cause of implementing SE-0155 
,
 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 
.
  The Core Team indicated in their rationale 

 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