[Review] SE-0155: Normalize Enum Case Representation

Before I start revising this proposal, there are a couple of open questions I’d like to discuss with the community and the core team.

The first question relates to the purpose of having a “internal” argument name. There are applications of such names in GADT (if we ever get there) and perhaps the case-as-subtype-of-the-enum stories on the list right now. Out side of these scenarios, however, such names has few chances to be used. The one I can come up with, which is also the “open” part of the question, is this: we can use the internal names in pattern matching, as opposed to using the labels. This seems to align with the subtyping/GADT use cases. Is this a desirable outcome?

Why would GADTs make internal argument names useful? They seem completely useless to me. Their "internal"-ness is compromised if you try to hang semantics off of them—they shouldn't have any impact on use sites.

Interesting.

I was reaching for any possible use cases there. The theory is these names would be how one refers to a "property" of the case in, say, extension methods for the case.

But yeah, I considered this internal name thing during first draft and decided that they weren't necessary :woman_shrugging:

I think the strongest argument here is that internal names already have an accepted meaning, which is just that they name the argument variables in the following code. Today, cases don't have any following code, but if/when we add that in SE-9999, people will obviously expect internal names to name those argument variables. Even if the SE-9999 proposers decide that, actually, using internal names for case arguments isn't a good idea, they will still need to do something about that natural user expectation, and they shouldn't be limited by us having carelessly given internal names some random other meaning way back in SE-0155.

John.

···

On Feb 27, 2017, at 1:39 PM, Daniel Duan <daniel@duan.org> wrote:

On Feb 27, 2017, at 10:00 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel@duan.org> wrote:

The second open question is the syntax for “overloaded” cases. If we decide to allow them, what should the patterns matching them look like? I can think of one obvious-ish design where we make the pattern look like the declaration and require types for disambiguation. So the most verbose form of pattern would look something like

case let .baseName(label0 name0: Type0, label1 name1: Type1)

By "overloaded", do you mean "same name different types", or "same base name, different argument names"? I think we should have a consistent naming model where the latter is never considered overloading.

Same name different type is what "overloading" was meant here. "Same base name" is already in the first revision and wouldn't fit in this "open question" discussion.

As an affordance to make pattern matching more concise, it seems reasonable to me to maybe say that a binding pattern matches a label with the same name, so that `case .foo(let bar, let bas)` can match `.foo(bar:bas:)`.

Good idea.

-Joe

Before I start revising this proposal, there are a couple of open questions I’d like to discuss

with the community and the core team.

The first question relates to the purpose of having a “internal”
argument name. There are applications of such names in GADT (if we
ever get there) and perhaps the case-as-subtype-of-the-enum stories
on the list right now. Out side of these scenarios, however, such
names has few chances to be used. The one I can come up with, which
is also the “open” part of the question, is this: we can use the
internal names in pattern matching, as opposed to using the
labels. This seems to align with the subtyping/GADT use cases. Is
this a desirable outcome?

Why would GADTs make internal argument names useful?

I'll probably never win this fight, but I'm trying to get people to use
“parameter name” and “argument label” as the preferred terms.

I like this terminology. I’ll start using it. Thanks for making an attempt to get everyone on the same page! :)

···

On Feb 27, 2017, at 4:07 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org> wrote:
on Mon Feb 27 2017, Joe Groff <jgroff-AT-apple.com> wrote:

On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel@duan.org> wrote:

They seem completely useless to me. Their "internal"-ness is
compromised if you try to hang semantics off of them—they shouldn't
have any impact on use sites.

The second open question is the syntax for “overloaded” cases. If we
decide to allow them, what should the patterns matching them look
like? I can think of one obvious-ish design where we make the
pattern look like the declaration and require types for
disambiguation. So the most verbose form of pattern would look
something like

case let .baseName(label0 name0: Type0, label1 name1: Type1)

By "overloaded", do you mean "same name different types", or "same
base name, different argument names"?

When you write "argument name," do you mean parameter name or argument
label? This is an example of why I'd like us to settle on the other
terminology.

I think we should have a consistent naming model where the latter is
never considered overloading. As an affordance to make pattern
matching more concise, it seems reasonable to me to maybe say that a
binding pattern matches a label with the same name, so that `case
.foo(let bar, let bas)` can match `.foo(bar:bas:)`.

SGTM

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

Yeah, how hard something is to type is very rarely more important than
how hard it is to read.

···

on Mon Feb 27 2017, Matthew Johnson <matthew-AT-anandabits.com> wrote:

On Feb 27, 2017, at 12:46 PM, Joe Groff <jgroff@apple.com> wrote:

That still feels like it's going against the behavior of the binding
name in other declarations. Personally, `case .playing(with: let x)`
doesn't bother me that much, especially since the IDE ought to be
able to splat that out for you.

It depends on how verbose the label is. :)

--
-Dave

Having watched this conversation from the sidelines, I just wanted to chime
in from a more distant view:

Originally, I thought this proposal was very nice because it made a good
argument as to why enum cases would benefit from being function-like. It
follows naturally that form should follow function, and therefore it's hard
to argue that the syntax shouldn't be "rectified."

But, given the latest discussions, it seems that there's a bunch of
round-peg-square-hole efforts going on precisely because enum cases
*aren't* very function-like in some key respects:

- John McCall gives a cogent reason why parameter names and argument labels
would be inconsistently used if they are put to the purpose that some have
proposed here for enum cases.

- There's a lot of bikeshedding as to pattern matching with argument
labels, as it seems that people generally agree that always requiring them
in that scenario would make the experience of using enums worse rather than
better. In fact, it seems that what's cited as a shortcoming in the
original proposal ("labels in patterns aren't enforced") is precisely what
we're trying to invent new sugar to duplicate.

Now, since we clearly want enum cases to be tuple-like in some respects
(pattern matching) but function-like in other respects, is swinging from
one extreme ("cases are tuples!") to the other ("cases are functions!") the
right thing to do? Does it really make the language more "consistent"?

···

On Mon, Feb 27, 2017 at 4:10 PM, Matthew Johnson via swift-evolution < swift-evolution@swift.org> wrote:

> On Feb 27, 2017, at 4:07 PM, Dave Abrahams via swift-evolution < > swift-evolution@swift.org> wrote:
>
>
> on Mon Feb 27 2017, Joe Groff <jgroff-AT-apple.com> wrote:
>
>>> On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel@duan.org> wrote:
>>>
>>> Before I start revising this proposal, there are a couple of open
questions I’d like to discuss
>> with the community and the core team.
>>>
>>> The first question relates to the purpose of having a “internal”
>>> argument name. There are applications of such names in GADT (if we
>>> ever get there) and perhaps the case-as-subtype-of-the-enum stories
>>> on the list right now. Out side of these scenarios, however, such
>>> names has few chances to be used. The one I can come up with, which
>>> is also the “open” part of the question, is this: we can use the
>>> internal names in pattern matching, as opposed to using the
>>> labels. This seems to align with the subtyping/GADT use cases. Is
>>> this a desirable outcome?
>>
>> Why would GADTs make internal argument names useful?
>
> I'll probably never win this fight, but I'm trying to get people to use
> “parameter name” and “argument label” as the preferred terms.

I like this terminology. I’ll start using it. Thanks for making an
attempt to get everyone on the same page! :)

>
>> They seem completely useless to me. Their "internal"-ness is
>> compromised if you try to hang semantics off of them—they shouldn't
>> have any impact on use sites.
>>
>>> The second open question is the syntax for “overloaded” cases. If we
>>> decide to allow them, what should the patterns matching them look
>>> like? I can think of one obvious-ish design where we make the
>>> pattern look like the declaration and require types for
>>> disambiguation. So the most verbose form of pattern would look
>>> something like
>>>
>>> ```
>>> case let .baseName(label0 name0: Type0, label1 name1: Type1)
>>> ```
>>
>> By "overloaded", do you mean "same name different types", or "same
>> base name, different argument names"?
>
> When you write "argument name," do you mean parameter name or argument
> label? This is an example of why I'd like us to settle on the other
> terminology.
>
>> I think we should have a consistent naming model where the latter is
>> never considered overloading. As an affordance to make pattern
>> matching more concise, it seems reasonable to me to maybe say that a
>> binding pattern matches a label with the same name, so that `case
>> .foo(let bar, let bas)` can match `.foo(bar:bas:)`.
>
> SGTM
>
> --
> -Dave
> _______________________________________________
> 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

--
Brent Royal-Gordon
Sent from my iPhone

Here is an example of the kind of thing I have in mind:

enum PlayerState {
case stopped
sub case playing(with track: Track)

  // type of the playing case looks something like this:
  struct Playing { let track: Track }

  // the case value constructor looks something like this
  static func playing(with track: Track) -> Playing {
      return Playing(track: track)
  }
}

Consider a different desugaring that leads to a different conclusion:

enum PlayerState {
case struct stopped {
   init() {}
   // I have some truly remarkable thoughts
   // on types like this one, which this margin
   // is too narrow to contain.
}
case struct playing {
   let track: Track
   init(track: Track) {
     self.track = track
   }
}

In this design, because the associated values on a case are really defining an initializer on a type, it would be against Swift conventions to use a parameter label like `with` instead of the actually-meaningful `track`. So the solution to this kind of problem is simply "Don't do that".

This example isn’t great. It was the first reasonable thing that came to mind to try and illustrate how I see argument labels and parameter / property names fitting in here.

I don’t agree with this perspective because enum cases are not accessed using a type name. When you use a type name to directly call an initializer it makes sense to use the property names for the labels.

When we have a static factory method that uses a private initializer to construct a value we *do not* necessarily follow this convention of using property names directly. We use a more sentence-like structure with external labels. Enum cases more closely match the way static factory methods are used so I think this is the proper way to conceptualize them when we are talking about using them to construct values.

···

On Feb 27, 2017, at 9:53 PM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Feb 27, 2017, at 10:39 AM, Matthew Johnson via swift-evolution <swift-evolution@swift.org> wrote:

--
Brent Royal-Gordon
Sent from my iPhone

My observations of this discussion so far:

First of all, I think there’s no inherent conflict in "making enum constructors look like function" and “making patterns look like tuple”. These can and should be considered orthogonal aspects of enum in the language.

At the risk of over simplifying, I’d like to pick a few conflicting design choices that came up and put them in two columns.

Column A argues for simplicity of the language, better teachability and perhaps more consistency. In this column we have:

1. Enum constructors: Be like functions, have parameter names as well as argument labels.
2. Argument labels in patterns: Require argument label, making patterns look more like the declaration
3. Binding name in patterns: Require matching with argument labels (or maybe parameter names)

Column B argues for better ergonomics and authoring experience, even improved readability in same cases:

1. Enum constructors: Do not introduce parameter names (until we have concrete uses for them in the future)
2. Argument labels in patterns: Allow skipping of all argument labels, matching by position.
3. Binding name in patterns: Allow arbitrary names (or only allow such bindings when labels are supplied)

Here’s they are again for those with GUI/Web email clients:

There are things that doesn’t fit (overloading cases by type, for example, makes the constructors more consistent with functions, but it’s unclear whether it makes the language simpler or more complex).

Both the first revision of this proposal and the next are “a little from column A and a little from column B”. But neither column is *wrong* really. I’m confident that we are *not* doomed!

···

On Feb 27, 2017, at 7:17 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Having watched this conversation from the sidelines, I just wanted to chime in from a more distant view:

Originally, I thought this proposal was very nice because it made a good argument as to why enum cases would benefit from being function-like. It follows naturally that form should follow function, and therefore it's hard to argue that the syntax shouldn't be "rectified."

But, given the latest discussions, it seems that there's a bunch of round-peg-square-hole efforts going on precisely because enum cases *aren't* very function-like in some key respects:

- John McCall gives a cogent reason why parameter names and argument labels would be inconsistently used if they are put to the purpose that some have proposed here for enum cases.

- There's a lot of bikeshedding as to pattern matching with argument labels, as it seems that people generally agree that always requiring them in that scenario would make the experience of using enums worse rather than better. In fact, it seems that what's cited as a shortcoming in the original proposal ("labels in patterns aren't enforced") is precisely what we're trying to invent new sugar to duplicate.

Now, since we clearly want enum cases to be tuple-like in some respects (pattern matching) but function-like in other respects, is swinging from one extreme ("cases are tuples!") to the other ("cases are functions!") the right thing to do? Does it really make the language more "consistent"?

On Mon, Feb 27, 2017 at 4:10 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Feb 27, 2017, at 4:07 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>
> on Mon Feb 27 2017, Joe Groff <jgroff-AT-apple.com> wrote:
>
>>> On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel@duan.org <mailto:daniel@duan.org>> wrote:
>>>
>>> Before I start revising this proposal, there are a couple of open questions I’d like to discuss
>> with the community and the core team.
>>>
>>> The first question relates to the purpose of having a “internal”
>>> argument name. There are applications of such names in GADT (if we
>>> ever get there) and perhaps the case-as-subtype-of-the-enum stories
>>> on the list right now. Out side of these scenarios, however, such
>>> names has few chances to be used. The one I can come up with, which
>>> is also the “open” part of the question, is this: we can use the
>>> internal names in pattern matching, as opposed to using the
>>> labels. This seems to align with the subtyping/GADT use cases. Is
>>> this a desirable outcome?
>>
>> Why would GADTs make internal argument names useful?
>
> I'll probably never win this fight, but I'm trying to get people to use
> “parameter name” and “argument label” as the preferred terms.

I like this terminology. I’ll start using it. Thanks for making an attempt to get everyone on the same page! :)

>
>> They seem completely useless to me. Their "internal"-ness is
>> compromised if you try to hang semantics off of them—they shouldn't
>> have any impact on use sites.
>>
>>> The second open question is the syntax for “overloaded” cases. If we
>>> decide to allow them, what should the patterns matching them look
>>> like? I can think of one obvious-ish design where we make the
>>> pattern look like the declaration and require types for
>>> disambiguation. So the most verbose form of pattern would look
>>> something like
>>>
>>> ```
>>> case let .baseName(label0 name0: Type0, label1 name1: Type1)
>>> ```
>>
>> By "overloaded", do you mean "same name different types", or "same
>> base name, different argument names"?
>
> When you write "argument name," do you mean parameter name or argument
> label? This is an example of why I'd like us to settle on the other
> terminology.
>
>> I think we should have a consistent naming model where the latter is
>> never considered overloading. As an affordance to make pattern
>> matching more concise, it seems reasonable to me to maybe say that a
>> binding pattern matches a label with the same name, so that `case
>> .foo(let bar, let bas)` can match `.foo(bar:bas:)`.
>
> SGTM
>
> --
> -Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto: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

It would absolutely make the implementation more consistent, since cases in expressions are the last vestige keeping a lot of damaged code in the type-checker alive to deal with argument label/tuple label ambiguity. Personally, I don't think that requiring labels in pattern matching is an undue burden, and I agree it's not a good idea to try to make up sugar to "un-require" them:

- It's totally self-imposed verbosity—nobody *has* to label their case payloads, and if you feel compelled to, it must be for a good reason. In my mind, those reasons shouldn't come up that often in practice, since enums with compound payloads are often better factored into a combination of enums and structs, and single-element payloads are best left unlabeled, like `some` or `string`/`number`/`array`/`object`.
- In general, pattern-matching syntax ought to behave as a mirror image of the expression that constructs a matching value, with holes punched into it via '_' or 'let' subpatterns. A lot of people already struggle with the concept, and unnecessary divergence from the behavior of expressions is added complexity. We already have too many inconsistencies in this area (implicit conversions in expressions don't fire in patterns; some pattern forms are artificially hardcoded to only look up enum cases; there are weird and technically redundant forms like "is T") that make learning patterns difficult.

-Joe

···

On Feb 27, 2017, at 7:17 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

Having watched this conversation from the sidelines, I just wanted to chime in from a more distant view:

Originally, I thought this proposal was very nice because it made a good argument as to why enum cases would benefit from being function-like. It follows naturally that form should follow function, and therefore it's hard to argue that the syntax shouldn't be "rectified."

But, given the latest discussions, it seems that there's a bunch of round-peg-square-hole efforts going on precisely because enum cases *aren't* very function-like in some key respects:

- John McCall gives a cogent reason why parameter names and argument labels would be inconsistently used if they are put to the purpose that some have proposed here for enum cases.

- There's a lot of bikeshedding as to pattern matching with argument labels, as it seems that people generally agree that always requiring them in that scenario would make the experience of using enums worse rather than better. In fact, it seems that what's cited as a shortcoming in the original proposal ("labels in patterns aren't enforced") is precisely what we're trying to invent new sugar to duplicate.

Now, since we clearly want enum cases to be tuple-like in some respects (pattern matching) but function-like in other respects, is swinging from one extreme ("cases are tuples!") to the other ("cases are functions!") the right thing to do? Does it really make the language more "consistent"?

Having watched this conversation from the sidelines, I just wanted to chime in from a more distant view:

Originally, I thought this proposal was very nice because it made a good argument as to why enum cases would benefit from being function-like. It follows naturally that form should follow function, and therefore it's hard to argue that the syntax shouldn't be "rectified."

But, given the latest discussions, it seems that there's a bunch of round-peg-square-hole efforts going on precisely because enum cases *aren't* very function-like in some key respects:

- John McCall gives a cogent reason why parameter names and argument labels would be inconsistently used if they are put to the purpose that some have proposed here for enum cases.

- There's a lot of bikeshedding as to pattern matching with argument labels, as it seems that people generally agree that always requiring them in that scenario would make the experience of using enums worse rather than better. In fact, it seems that what's cited as a shortcoming in the original proposal ("labels in patterns aren't enforced") is precisely what we're trying to invent new sugar to duplicate.

I didn’t write the proposal so I won’t comment directly on the motivation section. The reason I think not enforcing labels is a problem in the current rules is because allowing this does not convey the meaning of the associated value to a reader of the pattern. The suggestions for syntactic sugar to allow eliding a label avoids this problem altogether. I don’t think label elision is that complicated rule to teach and it could improve clarity of code nontrivially.

I have personally found a tension between using labels and having patterns that are quite unfortunately verbose. One can avoid this today by leaving off the label and being responsible with the name you assign. I would like to keep the concise nature of leaving off the labels while being assured that a reasonable name is used.

Now, since we clearly want enum cases to be tuple-like in some respects (pattern matching) but function-like in other respects, is swinging from one extreme ("cases are tuples!") to the other ("cases are functions!") the right thing to do? Does it really make the language more "consistent”?

My view is that it is a mistake to try to pidgeonhole enum cases into *one* of the roles they play. They actually play a couple of roles and we should acknowledge and consider each of these in designing the language.

The way I view enum cases is as a static factory method that produces a value which may be structurally matched using a pattern accessible via the base name of the case. I don’t see any reason why we should have to adopt one view or the other. Both are true and should be embraced.

enum Foo {
   case bar(argumentLabel propertyName: Int)
}

Is a lot like this in a hypothetical Swift with value subtyping and structural decomposition / matching of structs:

struct Foo {
   struct Bar: Foo { let propertyName: Int }
   static func bar(argumentLabel parameterName: Int) -> Bar {
      return Bar(propertyName: parameterName)
   }
}

switch Foo.bar(argumentLabel: 42) as Foo {
   case let (propertyName: let propertyValue): print(“value is \(propertyValue)”) as Bar
}

The only important differences are that this *requires* subtyping, and it does not allow the pattern to be accessed on Foo. One can even imaging syntax allowing the pattern to be accessible on `Foo` using a name `bar`:

extension Foo {
   pattern bar = // syntax which sets up a structural match of Bar values inside the parens when users type `.bar(structural match of Bar value here)`
}

···

On Feb 27, 2017, at 9:17 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote:

On Mon, Feb 27, 2017 at 4:10 PM, Matthew Johnson via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

> On Feb 27, 2017, at 4:07 PM, Dave Abrahams via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:
>
>
> on Mon Feb 27 2017, Joe Groff <jgroff-AT-apple.com> wrote:
>
>>> On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel@duan.org <mailto:daniel@duan.org>> wrote:
>>>
>>> Before I start revising this proposal, there are a couple of open questions I’d like to discuss
>> with the community and the core team.
>>>
>>> The first question relates to the purpose of having a “internal”
>>> argument name. There are applications of such names in GADT (if we
>>> ever get there) and perhaps the case-as-subtype-of-the-enum stories
>>> on the list right now. Out side of these scenarios, however, such
>>> names has few chances to be used. The one I can come up with, which
>>> is also the “open” part of the question, is this: we can use the
>>> internal names in pattern matching, as opposed to using the
>>> labels. This seems to align with the subtyping/GADT use cases. Is
>>> this a desirable outcome?
>>
>> Why would GADTs make internal argument names useful?
>
> I'll probably never win this fight, but I'm trying to get people to use
> “parameter name” and “argument label” as the preferred terms.

I like this terminology. I’ll start using it. Thanks for making an attempt to get everyone on the same page! :)

>
>> They seem completely useless to me. Their "internal"-ness is
>> compromised if you try to hang semantics off of them—they shouldn't
>> have any impact on use sites.
>>
>>> The second open question is the syntax for “overloaded” cases. If we
>>> decide to allow them, what should the patterns matching them look
>>> like? I can think of one obvious-ish design where we make the
>>> pattern look like the declaration and require types for
>>> disambiguation. So the most verbose form of pattern would look
>>> something like
>>>
>>> ```
>>> case let .baseName(label0 name0: Type0, label1 name1: Type1)
>>> ```
>>
>> By "overloaded", do you mean "same name different types", or "same
>> base name, different argument names"?
>
> When you write "argument name," do you mean parameter name or argument
> label? This is an example of why I'd like us to settle on the other
> terminology.
>
>> I think we should have a consistent naming model where the latter is
>> never considered overloading. As an affordance to make pattern
>> matching more concise, it seems reasonable to me to maybe say that a
>> binding pattern matches a label with the same name, so that `case
>> .foo(let bar, let bas)` can match `.foo(bar:bas:)`.
>
> SGTM
>
> --
> -Dave
> _______________________________________________
> swift-evolution mailing list
> swift-evolution@swift.org <mailto:swift-evolution@swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Having watched this conversation from the sidelines, I just wanted to chime in from a more distant view:

Originally, I thought this proposal was very nice because it made a good argument as to why enum cases would benefit from being function-like. It follows naturally that form should follow function, and therefore it's hard to argue that the syntax shouldn't be "rectified."

But, given the latest discussions, it seems that there's a bunch of round-peg-square-hole efforts going on precisely because enum cases *aren't* very function-like in some key respects:

- John McCall gives a cogent reason why parameter names and argument labels would be inconsistently used if they are put to the purpose that some have proposed here for enum cases.

- There's a lot of bikeshedding as to pattern matching with argument labels, as it seems that people generally agree that always requiring them in that scenario would make the experience of using enums worse rather than better. In fact, it seems that what's cited as a shortcoming in the original proposal ("labels in patterns aren't enforced") is precisely what we're trying to invent new sugar to duplicate.

Now, since we clearly want enum cases to be tuple-like in some respects (pattern matching) but function-like in other respects, is swinging from one extreme ("cases are tuples!") to the other ("cases are functions!") the right thing to do? Does it really make the language more "consistent"?

It would absolutely make the implementation more consistent, since cases in expressions are the last vestige keeping a lot of damaged code in the type-checker alive to deal with argument label/tuple label ambiguity. Personally, I don't think that requiring labels in pattern matching is an undue burden, and I agree it's not a good idea to try to make up sugar to "un-require" them:

- It's totally self-imposed verbosity—nobody *has* to label their case payloads, and if you feel compelled to, it must be for a good reason. In my mind, those reasons shouldn't come up that often in practice, since enums with compound payloads are often better factored into a combination of enums and structs, and single-element payloads are best left unlabeled, like `some` or `string`/`number`/`array`/`object`.

I agree with you about factoring out compound payloads. If we could pattern match structs as well as declare and use a `case struct` with lightweight syntax I’m not sure I would use compound cases at all anymore.

- In general, pattern-matching syntax ought to behave as a mirror image of the expression that constructs a matching value, with holes punched into it via '_' or 'let' subpatterns. A lot of people already struggle with the concept, and unnecessary divergence from the behavior of expressions is added complexity. We already have too many inconsistencies in this area (implicit conversions in expressions don't fire in patterns; some pattern forms are artificially hardcoded to only look up enum cases; there are weird and technically redundant forms like "is T") that make learning patterns difficult.

This is a fair point.

···

On Feb 28, 2017, at 10:39 AM, Joe Groff <jgroff@apple.com> wrote:

On Feb 27, 2017, at 7:17 PM, Xiaodi Wu via swift-evolution <swift-evolution@swift.org> wrote:

-Joe