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

Xiaodi Wu xiaodi.wu at gmail.com
Thu Apr 20 15:39:18 CDT 2017


On Thu, Apr 20, 2017 at 3:20 PM, John McCall via swift-evolution <
swift-evolution at swift.org> wrote:

> Proposal Link: https://github.com/apple/swift-evolution/blob/
> master/proposals/0155-normalize-enum-case-representation.md
>
> Hello Swift Community,
>
> The review of SE-0155 "Normalize Enum Case Representation” ran from March
> 31st through April 10th, 2017. The proposal is *accepted with revisions*.
>
> Feedback from the community was positive about most aspects of the
> proposal.  However, there was substantial disagreement about the right
> direction for pattern matching.  The core team discussed this issue in
> depth.
>
> Pattern matching is central to the use of enum types.  It's the only way
> you can use an enum value, besides general operations like passing it to a
> function or the special affordances for Optionals.  Pattern matching is as
> central to enums as stored property access is to structs, and it's fair to
> be worried about anything that would make it substantially more onerous.
> Unconditionally requiring associated-value labels in case patterns would
> certainly do that, and several members of the core team expressed concern
> that it would be bad enough to discourage the use of associated-value
> labels completely — in effect, subverting the entire language feature being
> proposed.
>
> It is true that including associated-value labels in case patterns does
> preserve a great deal of information in the source code:
>
>   - This information can usefully contribute to the clarity of the code
> following the pattern.
>
>   - Hiding this information can lead to bugs that would be self-evident if
> the case labels were always included.  For example, if a case payload
> included a number of different boolean flags, it would be easy for a
> pattern to accidentally label them in the wrong order.
>
>   - Finally, this information may be necessary in order to determine which
> case is being matched, since the proposal adds the ability to distinguish
> cases purely by the labels on associated values.
>
> However, the core team feels that there are counter-arguments which weaken
> the force of these considerations:
>
>   - 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.  Therefore, the core teams revises the proposal as
> follows:
>
> A case pattern may omit labels for the associated values of a case if
> there is only one case with the same base name and arity.  A pattern must
> omit all labels if it omits any of them; thus, a case pattern either
> exactly matches the full name of a case or has no labels at all.  For
> example:
>
>   enum E {
>     case often(first: Int, second: Int)
>     case lots(first: Int, second: Int)
>     case many(value: Int)
>     case many(first: Int, second: Int)
>     case many(alpha: Int, beta: Int)
>     case sometimes(value: Int)
>     case sometimes(Int)
>   }
>
>   switch e {
>   // Valid: the sequence of labels exactly matches a case name.
>   case .often(first: let a, second: let b):
>     ...
>
>   // Valid: there is only one case with this base name.
>   case .lots(let a, let b):
>     ...
>
>   // Valid: there is only one case with this base name and payload count.
>   case .many(let a):
>     ...
>
>   // Invalid: there are multiple cases with this base name and payload
> count.
>   case .many(let a, let b):
>     ...
>
>   // Valid: the sequence of labels exactly matches a case name.
>   case .many(first: let a, second: let b):
>     ...
>
>   // Invalid: includes a label, but not on all of the labelled arguments.
>   case .same(alpha: let a, let b):
>     ...
>
>   // Valid: the sequence of labels exactly matches a case name (that
> happens to not provide any labels).
>   case .sometimes(let x):
>     ...
>
>   // Invalid: includes a label, but there is no matching case.
>   case .sometimes(badlabel: let x):
>     ...
>   }
>
> This only affects case patterns.  Constructing a case always requires that
> any associated value labels in the case name be provided.
>
> A case pattern must include patterns for all associated values of the
> case, even if the associated value has a default value.  We may choose to
> relax this rule in a future release, or generally provide some sort of
> "..." syntax for indicating that there are associated values being ignored.
>

I assume that the following is obvious and the core team's intention, but
it bears confirmation and being documented:

```
enum F {
  case many(first: Int, second: Int)
  case many(Int, Int)
  case withDefaultValue(Int, Int, Int=42)
  case withDefaultValue(first: Int, second: Int, third: Int=42)
  case withDefaultValue(first: Int, second: Int, notThirdToMakeAPoint:
Int=43)
}

switch f {
// Valid, even though multiple cases have this base name and arity,
// because it is an exact match for a case that provides no labels.
case .many(let a, let b):
  break

// Invalid, as case pattern must include even values with default.
case .withDefaultValue(let a, let b):
  break

// Valid, as inclusion doesn't mean binding.
case .withDefaultValue(let a, let b, _):
  break

// Valid, for the same reason as above.
case .withDefaultValue(first: let a, second: let b, third: _):
  break

// Invalid, because the label is part of what's required, even if using `_`,
// since otherwise it could be ambiguous as to which case is being matched.
case .withDefaultValue(first: let a, second: let b, _):
  break
}
```


The proposal includes a rule inferring labels in case patterns from binding
> names.  The core team feels that imparting local variable names with this
> kind of significance would be unprecedented, surprising, and rather
> "pushy".  The goal of this rule is also largely achieved by the new rule
> allowing labels to be omitted regardless of binding.  Accordingly, this
> rule is struck from the proposal.  That said, it would be a good idea for
> the implementation to warn when a binding name matches the label for a
> different associated value.
>
> John McCall
> Review Manager
>
> _______________________________________________
> swift-evolution mailing list
> swift-evolution at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20170420/79cc67ab/attachment.html>


More information about the swift-evolution mailing list