<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I’ve incorporated feedbacks from this thread.<div class=""><br class=""></div><div class="">Rendered:&nbsp;<a href="https://github.com/dduan/swift-evolution/blob/compound-names-for-enum-cases/proposals/NNNN-Normalize-Enum-Case-Representation.md" class="">https://github.com/dduan/swift-evolution/blob/compound-names-for-enum-cases/proposals/NNNN-Normalize-Enum-Case-Representation.md</a></div><div class=""><br class=""></div><div class="">—</div><div class=""><br class=""></div><div class=""><div class=""># Normalize Enum Case Representation</div><div class=""><br class=""></div><div class="">* Proposal: [SE-NNNN][]</div><div class="">* Authors: [Daniel Duan][], [Joe Groff][]</div><div class="">* Review Manager: TBD</div><div class="">* Status: **Awaiting review**</div><div class=""><br class=""></div><div class="">## Introduction</div><div class=""><br class=""></div><div class="">In Swift 3, associated values for an enum case are represented by</div><div class="">a labeled-tuple. This has several undesired effects: inconsistency in enum value</div><div class="">construction syntax, many forms of pattern matching, missing features such as</div><div class="">specifying default value and missed opportunity for layout improvements.</div><div class=""><br class=""></div><div class="">This proposal aims to make enums more "regular" by replacing tuple as the</div><div class="">representation of associated values, making declaration and construction of enum</div><div class="">cases more function-like.</div><div class=""><br class=""></div><div class="">Swift-evolution thread: [Compound Names For Enum Cases][SE Thread]</div><div class=""><br class=""></div><div class="">## Motivation</div><div class=""><br class=""></div><div class="">**Each enum case declares a function that can be used to create a corresponding</div><div class="">value. To users who expect these functions to behave "normally", surprises</div><div class="">await.**</div><div class=""><br class=""></div><div class="">1. Associated value labels aren't part of the function name.</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; After [SE-0111][] Swift function's fully qualified name consists of its</div><div class="">&nbsp; &nbsp; base-name and all argument labels. As an illustration, one can invoke</div><div class="">&nbsp; &nbsp; a function with its full name:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; ```swift</div><div class="">&nbsp; &nbsp; func f(x: Int, y: Int) {}</div><div class="">&nbsp; &nbsp; f(x: y:)(0, 0) // Okay, this is equivalent to f(x: 0, y: 0)</div><div class="">&nbsp; &nbsp; ```</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; This, however, cannot be done when enum cases with associated value were</div><div class="">&nbsp; &nbsp; constructed:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; ```swift</div><div class="">&nbsp; &nbsp; enum Foo {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; case bar(x: Int, y: Int)</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; Foo.bar(x: y:)(0, 0) // Does not compile as of Swift 3</div><div class="">&nbsp; &nbsp; ```</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; Here, `x` and `y` are labels of bar's payload (a tuple), as opposed to being</div><div class="">&nbsp; &nbsp; part of the case's formal name. This is inconsistent with rest of the</div><div class="">&nbsp; &nbsp; language.</div><div class=""><br class=""></div><div class="">2. Default value for parameters isn't available in case declarations.</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; ```swift</div><div class="">&nbsp; &nbsp; enum Animation {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; case fadeIn(duration: TimeInterval = 0.3) // Nope!</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; let anim = Animation.fadeIn() // Would be nice, too bad!</div><div class="">&nbsp; &nbsp; ```</div><div class=""><br class=""></div><div class="">**Associated values being a tuple complicates pattern matching.**</div><div class=""><br class=""></div><div class="">The least unexpected pattern to match a `bar` value is the following:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">if case let .bar(x: p, y: q) = Foo.bar(x: 0, y: 1) {</div><div class="">&nbsp; &nbsp; print(p, q) // 0 1</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">In Swift 3, there are a few alternatives that may not be obvious to new users.</div><div class=""><br class=""></div><div class="">1. A pattern with a single value would match and result in a tuple:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; ```swift</div><div class="">&nbsp; &nbsp; if case let .bar(wat) = Foo.bar(x: 0, y: 1) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; print(wat.y) // 1</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; ```</div><div class=""><br class=""></div><div class="">2. Labels in patterns are not enforced:</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; ```swift</div><div class="">&nbsp; &nbsp; // note: there's no label in the following pattern</div><div class="">&nbsp; &nbsp; if case let .bar(p, q) = Foo.bar(x: 0, y: 1) {</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; print(p, q) // 0 1</div><div class="">&nbsp; &nbsp; }</div><div class="">&nbsp; &nbsp; ```</div><div class=""><br class=""></div><div class="">These complex rules makes pattern matching difficult to teach and to expand to</div><div class="">other types.</div><div class=""><br class=""></div><div class="">**Moving away from tuple-as-associated-value also give us opportunity to improve</div><div class="">enum's memory layout** since each associated value would no longer play double</div><div class="">duty as part of the tuple's memory layout.</div><div class=""><br class=""></div><div class="">## Proposed Solution</div><div class=""><br class=""></div><div class="">When a enum case has associated values, they will no longer form a tuple. Their</div><div class="">labels will become part of the case's declared name. Patterns matching such</div><div class="">value must include labels in order matching the declaration.</div><div class=""><br class=""></div><div class="">This proposal also introduce the ability to include a default value for each</div><div class="">associated value in the declaration.</div><div class=""><br class=""></div><div class="">## Detailed Design</div><div class=""><br class=""></div><div class="">### Make associated value labels part of case's name</div><div class="">When labels are present in enum case's payload, they will become part of case's</div><div class="">declared name instead of being labels for fields in a tuple. &nbsp;In details, when</div><div class="">constructing an enum value with the case name, label names must either be</div><div class="">supplied in the argument list it self, or as part of the full name.</div><div class=""><br class=""></div><div class="">```swift</div><div class="">Foo.bar(x: 0, y: 0) // Okay, the Swift 3 way.</div><div class="">Foo.bar(x: y:)(0, 0) // Equivalent to the previous line.</div><div class="">Foo.bar(x: y:)(x: 0, y: 0) // This would be an error, however.</div><div class="">```</div><div class=""><br class=""></div><div class="">Note that since the labels aren't part of a tuple, they no longer participate in</div><div class="">type checking, similar to functions:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">let f = Foo.bar // f has type (Int, Int) -&gt; Foo</div><div class="">f(0, 0) // Okay!</div><div class="">f(x: 0, y: 0) // Won't compile.</div><div class="">```</div><div class=""><br class=""></div><div class="">### Add default value in enum case declarations</div><div class=""><br class=""></div><div class="">From a user's point view, declaring an enum case should remain the same as Swift</div><div class="">3 except now it's possible to add `= expression` after the type of an</div><div class="">associated value to convey a default value for that field. Updated syntax:</div><div class=""><br class=""></div><div class="">```ebnf</div><div class="">union-style-enum-case = enum-case-name [enum-case-associated-value-clause];</div><div class="">enum-case-associated-value-clause = "(" ")"</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | "(" enum-case-associated-value-list ")";</div><div class="">enum-case-associated-value-list = enum-associated-value-element</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | enum-associated-value-element ","</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enum-case-associated-value-list;</div><div class="">enum-case-associated-value-element = element-name type-annotation</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;[enum-case-element-default-value-clause]</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| type [enum-case-element-default-value-clause];</div><div class="">element-name = identifier;</div><div class="">enum-case-element-default-value-clause = "=" expression;</div><div class="">```</div><div class=""><br class=""></div><div class="">### Simplify pattern matching rules on enums</div><div class="">Syntax for enum case patterns will be the following:</div><div class=""><br class=""></div><div class="">```ebnf</div><div class="">enum-case-pattern = [type-identifier] "." enum-case-name [enum-case-associated-value-pattern];</div><div class="">enum-case-associated-value-pattern = "(" [enum-case-associated-value-list-pattern] ")";</div><div class="">enum-case-associated-value-list-pattern = enum-case-associated-value-list-pattern-element</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | enum-case-associated-value-list-pattern-element ","</div><div class="">&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; enum-case-associated-value-list-pattern;</div><div class="">enum-case-associated-value-list-element = pattern | identifier ":" pattern;</div><div class="">```</div><div class=""><br class=""></div><div class="">… and `case-associated-value-pattern` will be added to the list of various</div><div class="">`pattern`s.</div><div class=""><br class=""></div><div class="">Note that `enum-case-associated-value-pattern` is identical to `tuple-pattern`</div><div class="">except in names. It is introduced here to denote semantic difference between the</div><div class="">two. &nbsp;Whereas the syntax in Swift 3 allows a single `tuple-pattern-element` to</div><div class="">match the entire case payload, the number of</div><div class="">`enum-case-associated-value-list-pattern-element`s must be equal to that of</div><div class="">associated value of the case in order to be a match. This means this example</div><div class="">will be deprecated under this proposal:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">if case let .bar(wat) = Foo.bar(x: 0, y: 1) { // syntax error</div><div class="">&nbsp; &nbsp; // …</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">Further, `identifier` in `enum-case-associated-value-list-pattern-element` must</div><div class="">be the same as the label of corresponding associated value intended for the</div><div class="">match. So this will be deprecated as well:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">if case let .bar(p, q) = Foo.bar(x: 0, y: 1) { // missing `x:` and `y:`</div><div class="">&nbsp; &nbsp; // …</div><div class="">}</div><div class="">```</div><div class=""><br class=""></div><div class="">## Source compatibility</div><div class=""><br class=""></div><div class="">As detailed in the previous section, this proposal deprecates certain pattern</div><div class="">matching syntax.</div><div class=""><br class=""></div><div class="">Other changes to the syntax are additive and source compatible with Swift 3.</div><div class=""><br class=""></div><div class="">## Effect on ABI stability and resilience</div><div class=""><br class=""></div><div class="">After this proposal, enum cases may have compound names, which would be mangled</div><div class="">differently than Swift 3.</div><div class=""><br class=""></div><div class="">The compiler may also layout enums differently now that payloads are not</div><div class="">constrained by having to be part of a tuple.</div><div class=""><br class=""></div><div class="">## Alternative Considered</div><div class=""><br class=""></div><div class="">To maintain maximum source compatibility, we could introduce a rule that matches</div><div class="">all associated values to a labeled tuple. As T.J. Usiyan</div><div class="">[pointed out][TJs comment], implementation of the equality protocal would be</div><div class="">simplified due to tuple's conformance to `Equatable`. This feature may still be</div><div class="">introduced with alternative syntax (perhaps related to splats) later without</div><div class="">source-breakage. &nbsp;And the need to implement `Equatable` may also disappear with</div><div class="">auto-devriving for `Equitable` conformance.</div><div class=""><br class=""></div><div class="">A syntax that did stay for source compatibility is allowing `()` in patterns</div><div class="">that match enum cases without associated values:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">if let case .x() = Foo.baz { // … }</div><div class="">```</div><div class=""><br class=""></div><div class="">We could remove this syntax as it would make the pattern look more consistent to</div><div class="">the case's declaration.</div><div class=""><br class=""></div><div class="">[SE-0111]: <a href="https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md" class="">https://github.com/apple/swift-evolution/blob/master/proposals/0111-remove-arg-label-type-significance.md</a></div><div class="">[Daniel Duan]: <a href="https://github.com/dduan" class="">https://github.com/dduan</a></div><div class="">[Joe Groff]: <a href="https://github.com/jckarter" class="">https://github.com/jckarter</a></div><div class="">[SE-NNNN]: NNNN-Normalize-Enum-Case-Representation.md</div><div class="">[TJs comment]: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170116/030614.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170116/030614.html</a></div><div class="">[SE Thread]: <a href="https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170116/030477.html" class="">https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20170116/030477.html</a></div><div class=""><br class=""></div><div><blockquote type="cite" class=""><div class="">On Jan 19, 2017, at 10:37 AM, Daniel Duan via swift-evolution &lt;<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">Hi all,<div class=""><br class=""></div><div class="">Here’s a short proposal for fixing an inconsistency in Swift’s enum. Please share you feedback :)</div><div class=""><br class=""></div><div class="">(Updating/rendered version:&nbsp;<a href="https://github.com/dduan/swift-evolution/blob/compound-names-for-enum-cases/proposals/NNNN-Compound-Names-For-Enum-Cases.md" class="">https://github.com/dduan/swift-evolution/blob/compound-names-for-enum-cases/proposals/NNNN-Compound-Names-For-Enum-Cases.md</a>)</div><div class=""><br class=""></div><div class=""><br class=""></div><div class=""><div class="">## Introduction</div><div class=""><br class=""></div><div class="">Argument labels are part of its function's declaration name. An enum case</div><div class="">declares a function that can be used to construct enum values. For cases with</div><div class="">associated values, their labels should be part of the constructor name, similar</div><div class="">to "normal" function and methods. In Swift 3, however, this is not true. This</div><div class="">proposal aim to change that.</div><div class=""><br class=""></div><div class="">## Motivation</div><div class=""><br class=""></div><div class="">After SE-0111, Swift function's fully qualified name consists of its base name</div><div class="">and all argument labels. As a example, one can invoke a function with its</div><div class="">fully name:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">func f(x: Int, y: Int) {}</div><div class=""><br class=""></div><div class="">f(x: y:)(0, 0) // Okay, this is equivalent to f(x: 0, y: 0)</div><div class="">```</div><div class=""><br class=""></div><div class="">This, however, is not true when enum cases with associated value were</div><div class="">constructed:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">enum Foo {</div><div class="">&nbsp; &nbsp; case bar(x: Int, y: Int)</div><div class="">}</div><div class=""><br class=""></div><div class="">Foo.bar(x: y:)(0, 0) // Does not compile as of Swift 3</div><div class="">```</div><div class=""><br class=""></div><div class="">Here, the declared name for the case is `foo`; it has a tuple with two labeled</div><div class="">fields as its associated value. `x` and `y` aren't part of the case name. This</div><div class="">inconsistency may surprise some users.</div><div class=""><br class=""></div><div class="">Using tuple to implement associated value also limits us from certain layout</div><div class="">optimizations as each payload need to be a tuple first, as opposed to simply be</div><div class="">unique to the enum.</div><div class=""><br class=""></div><div class="">## Proposed solution</div><div class=""><br class=""></div><div class="">Include labels in enum case's declaration name. In the last example, `bar`'s</div><div class="">full name would become `bar(x:y:)`, `x` and `y` will no longer be labels in a</div><div class="">tuple. The compiler may also stop using tuple to represent associated values.</div><div class=""><br class=""></div><div class="">## Detailed design</div><div class=""><br class=""></div><div class="">When labels are present in enum cases, they are now part of case's declared name</div><div class="">instead of being labels for fields in a tuple. In details, when constructing an</div><div class="">enum value with the case name, label names must either be supplied in the</div><div class="">argument list it self, or as part of the full name.</div><div class=""><br class=""></div><div class="">```swift</div><div class="">Foo.bar(x: 0, y: 0) // Okay, the Swift 3 way.</div><div class="">Foo.bar(x: y:)(0, 0) // Equivalent to the previous line.</div><div class="">Foo.bar(x: y:)(x: 0, y: 0) // This would be an error, however.</div><div class="">```</div><div class=""><br class=""></div><div class="">Note that since the labels aren't part of a tuple, they no longer participate in</div><div class="">type checking, similar to functions:</div><div class=""><br class=""></div><div class="">```swift</div><div class="">let f = Foo.bar // f has type (Int, Int) -&gt; Foo</div><div class="">f(0, 0) // Okay!</div><div class="">f(x: 0, y: 0) // Won't compile.</div><div class="">```</div><div class=""><br class=""></div><div class="">## Source compatibility</div><div class=""><br class=""></div><div class="">Since type-checking rules on labeled tuple is stricter than that on function</div><div class="">argument labels, existing enum value construction by case name remain valid.</div><div class="">This change is source compatible with Swift 3.</div><div class=""><br class=""></div><div class="">## Effect on ABI stability and resilience</div><div class=""><br class=""></div><div class="">This change introduces compound names for enum cases, which affects their</div><div class="">declaration's name mangling.</div><div class=""><br class=""></div><div class="">The compiler may also choose to change enum payload's representation from tuple.</div><div class="">This may open up more space for improving enum's memory layout.</div><div class=""><br class=""></div><div class="">## Alternatives considered</div><div class=""><br class=""></div><div class="">Keep current behaviors, which means we live with the inconsistency.</div></div><div class=""><br class=""></div></div>_______________________________________________<br class="">swift-evolution mailing list<br class=""><a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a><br class="">https://lists.swift.org/mailman/listinfo/swift-evolution<br class=""></div></blockquote></div><br class=""></div></body></html>