<html><head><meta http-equiv="content-type" content="text/html; charset=utf-8"></head><body dir="auto"><div><br><br>Sent from my iPad</div><div><br>On Jan 23, 2017, at 3:32 PM, Joe Groff via swift-evolution <<a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a>> wrote:<br><br></div><blockquote type="cite"><div><meta http-equiv="Content-Type" content="text/html charset=utf-8">This looks pretty good! It might be worth calling out explicitly that matching a payloaded case by name alone still works, e.g.:<div class=""><br class=""></div><div class="">enum Foo { case foo(Int), bar(x: Int) }</div><div class=""><br class=""></div><div class="">switch Foo.foo(0) {</div><div class="">case .foo:</div><div class=""> break</div><div class="">case .bar(x:):</div><div class=""> break</div><div class="">}</div></div></blockquote><div><br></div>In your example would 'bar(x:)' be required or would a naked 'bar' also be valid? I'm guessing it would not be valid which strikes me as slightly unfortunate. This would create some unpleasant verbosity in some places that isn't required today. (Incidentally, a nontrivial amount of this code would be in easily derivable "isSameCase" equivalence relations that compare the case used but not the associated values)<div><div><br></div><div>Another question - if labels become part of the case name does that mean we can "overload" the base name?</div><div><br></div><div>enum Foo {</div><div> case bar(x: Int)</div><div> case bar(y: Int)</div><div>}</div><div><br></div><div>The example is intentionally problematic because I'm not sure this would be a good idea, but more realistic examples may be possible with cases more meaningfully distinguished by associated value labels. </div><div><br></div><div>This is an idea that naturally follows with a move to a more function-like model of enum cases with labels being part of the name so it's worth discussing whether or not it should be allowed.</div><div><br></div><br><blockquote type="cite"><div><div class=""><br class=""></div><div class="">-Joe<br class=""><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On Jan 23, 2017, at 11:38 AM, Daniel Duan <<a href="mailto:daniel@duan.org" class="">daniel@duan.org</a>> 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="">I’ve incorporated feedbacks from this thread.<div class=""><br class=""></div><div class="">Rendered: <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=""> After [SE-0111][] Swift function's fully qualified name consists of its</div><div class=""> base-name and all argument labels. As an illustration, one can invoke</div><div class=""> a function with its full name:</div><div class=""><br class=""></div><div class=""> ```swift</div><div class=""> func f(x: Int, y: Int) {}</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, cannot be done 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=""> case bar(x: Int, y: Int)</div><div 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, `x` and `y` are labels of bar's payload (a tuple), as opposed to being</div><div class=""> part of the case's formal name. This is inconsistent with rest of the</div><div class=""> 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=""> ```swift</div><div class=""> enum Animation {</div><div class=""> case fadeIn(duration: TimeInterval = 0.3) // Nope!</div><div class=""> }</div><div class=""> let anim = Animation.fadeIn() // Would be nice, too bad!</div><div class=""> ```</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=""> 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=""> ```swift</div><div class=""> if case let .bar(wat) = Foo.bar(x: 0, y: 1) {</div><div class=""> print(wat.y) // 1</div><div class=""> }</div><div class=""> ```</div><div class=""><br class=""></div><div class="">2. Labels in patterns are not enforced:</div><div class=""><br class=""></div><div class=""> ```swift</div><div class=""> // note: there's no label in the following pattern</div><div class=""> if case let .bar(p, q) = Foo.bar(x: 0, y: 1) {</div><div class=""> print(p, q) // 0 1</div><div class=""> }</div><div class=""> ```</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. 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) -> 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=""> | "(" enum-case-associated-value-list ")";</div><div class="">enum-case-associated-value-list = enum-associated-value-element</div><div class=""> | enum-associated-value-element ","</div><div class=""> enum-case-associated-value-list;</div><div class="">enum-case-associated-value-element = element-name type-annotation</div><div class=""> [enum-case-element-default-value-clause]</div><div class=""> | 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=""> | enum-case-associated-value-list-pattern-element ","</div><div class=""> 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. 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=""> // …</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=""> // …</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. 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 class=""><blockquote type="cite" class=""><div class="">On Jan 19, 2017, at 10:37 AM, Daniel Duan via swift-evolution <<a href="mailto:swift-evolution@swift.org" class="">swift-evolution@swift.org</a>> 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: <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=""> 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) -> 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=""><a href="https://lists.swift.org/mailman/listinfo/swift-evolution" class="">https://lists.swift.org/mailman/listinfo/swift-evolution</a><br class=""></div></blockquote></div><br class=""></div></div></div></blockquote></div><br class=""></div></div></div></blockquote><blockquote type="cite"><div><span>_______________________________________________</span><br><span>swift-evolution mailing list</span><br><span><a href="mailto:swift-evolution@swift.org">swift-evolution@swift.org</a></span><br><span><a href="https://lists.swift.org/mailman/listinfo/swift-evolution">https://lists.swift.org/mailman/listinfo/swift-evolution</a></span><br></div></blockquote></div></body></html>