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