[swift-evolution] [draft] Compound Names For Enum Cases

Matthew Johnson matthew at anandabits.com
Thu Jan 19 17:07:58 CST 2017


> On Jan 19, 2017, at 4:58 PM, Daniel Duan via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
>> On Jan 19, 2017, at 2:29 PM, Joe Groff <jgroff at apple.com <mailto:jgroff at apple.com>> wrote:
>> 
>>> 
>>> On Jan 19, 2017, at 1:47 PM, Douglas Gregor via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> wrote:
>>> 
>>> This looks totally reasonable to me. A couple of comments:
>>> 
>>> 1) Because this proposal is breaking the link between the associated value of an enum case and tuple types, I think it should spell out the rules that switch statements will use when matching an enum value against a a case with an associated value. Some kind of rules fell out of them being treated as tuple types, but they might not be what we want.
>> 
>> I was about to bring up the same. Right now, an enum pattern works like .<identifier> <tuple-pattern>, where the <tuple-pattern> then recursively matches the payload tuple. In this model, it seems like we'd want to treat it more like .<identifier>(<pattern>, <pattern>, ...). Similar to how we lost "tuple splatting" to forward a bunch of arguments, we'd have to decide whether we lose the ability to match all parts of the payload into a tuple.
> 
> I’m leaning towards “no” for simplicity of the language (and implementation). That means this would be source-breaking 😞.  Will update the proposal and see how the rest of the feedback goes.

I lean towards “no” as well.  I like the general direction of departing from treating associated values as tuples.  This opens the door to some additional features related to associated values that have been discussed from time to time.  

For example, one perennial topic seems to be a desire to treat associated values more like properties (there have been various different suggestions for how to do this).  When all cases define an associated value with the same name and type it really can be viewed very much like a property.  In other cases, it is possible to view them as read-only, optional properties.  I have encountered a number of cases where it has been useful to implement computed properties like this manually and could easily envision a language feature eventually eliminating the boilerplate.

> 
>> I also don't think we currently enforce matching argument labels, so you can match a `case foo(x: Int, y: Int)` with a `.foo(let q, let z)` or `.foo(apples: let x, bananas: let y)` pattern. We should probably tighten that up as part of this proposal as well.
>> 
>> -Joe
>> 
>>> 2) I wouldn’t blame you if you wanted to slip in default arguments for associated values here, because this is really making enum cases with associated values much more function-like
>>> 
>>> 	- Doug
>>> 
>>>> On Jan 19, 2017, at 10:37 AM, Daniel Duan via swift-evolution <swift-evolution at swift.org <mailto:swift-evolution at swift.org>> 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
>>>> swift-evolution at swift.org <mailto:swift-evolution at swift.org>
>>>> 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>
> _______________________________________________
> 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/20170119/e276a767/attachment.html>


More information about the swift-evolution mailing list