[swift-evolution] [swift-evolution-announce] [Review] SE-0155: Normalize Enum Case Representation

Matthew Johnson matthew at anandabits.com
Tue Feb 28 09:47:40 CST 2017


> On Feb 27, 2017, at 9:17 PM, Xiaodi Wu <xiaodi.wu at gmail.com> 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.

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 Mon, Feb 27, 2017 at 4:10 PM, Matthew Johnson via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
> 
> > On Feb 27, 2017, at 4:07 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at 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 at duan.org <mailto:daniel at 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 at swift.org <mailto:swift-evolution at swift.org>
> > https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
> https://lists.swift.org/mailman/listinfo/swift-evolution <https://lists.swift.org/mailman/listinfo/swift-evolution>
> 

-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170228/e0db4331/attachment.html>


More information about the swift-evolution mailing list