[swift-evolution] [swift-evolution-announce] [Review] SE-0155: Normalize Enum Case Representation
Matthew Johnson
matthew at anandabits.com
Mon Feb 27 12:57:14 CST 2017
> On Feb 27, 2017, at 12:46 PM, Joe Groff <jgroff at apple.com> wrote:
>
>
>> On Feb 27, 2017, at 10:39 AM, Matthew Johnson <matthew at anandabits.com> wrote:
>>
>>
>>
>> Sent from my iPad
>>
>>> On Feb 27, 2017, at 12:00 PM, Joe Groff via swift-evolution <swift-evolution at swift.org> wrote:
>>>
>>>
>>>> On Feb 24, 2017, at 9:26 PM, Daniel Duan <daniel at duan.org> wrote:
>>>>
>>>> Before I start revising this proposal, there are a couple of open questions I’d like to discuss with the community and the core team.
>>>>
>>>> The first question relates to the purpose of having a “internal” argument name. There are applications of such names in GADT (if we ever get there) and perhaps the case-as-subtype-of-the-enum stories on the list right now. Out side of these scenarios, however, such names has few chances to be used. The one I can come up with, which is also the “open” part of the question, is this: we can use the internal names in pattern matching, as opposed to using the labels. This seems to align with the subtyping/GADT use cases. Is this a desirable outcome?
>>>
>>> Why would GADTs make internal argument names useful? They seem completely useless to me. Their "internal"-ness is compromised if you try to hang semantics off of them—they shouldn't have any impact on use sites.
>>
>> Internal is probably a bad name. Imagine if the case is a subtype of the enum and thus a struct or struct-like type. We would usually want the property to be named similarly to the name we would use for an argument in a function implementation, not the label used when calling the function.
>>
>> Here is an example of the kind of thing I have in mind:
>>
>> enum PlayerState {
>> case stopped
>> sub case playing(with track: Track)
>>
>> // type of the playing case looks something like this:
>> struct Playing { let track: Track }
>>
>> // the case value constructor looks something like this
>> static func playing(with track: Track) -> Playing {
>> return Playing(track: track)
>> }
>> }
>>
>> let foo = Foo.playing(with: makeTrack())
>> let track = foo.track
>>
>> switch foo {
>> case .stopped: break
>> // we get to match with the name that is argument / property-like
>> // `with` would be a terrible variable name
>> case .playing(let track): // do something with the track
>>
>> // this label would be used when the user wants to use a *different* name
>> // case .playing(with: let someOtherName)
>> }
>
> That still feels like it's going against the behavior of the binding name in other declarations. Personally, `case .playing(with: let x)` doesn't bother me that much, especially since the IDE ought to be able to splat that out for you.
It depends on how verbose the label is. :)
What did you think of the subtype example using the “internal” name as the property name? Does that make sense?
I definitely don’t think we would want to allow eliding the *external* label by binding a name: `case .playing(let with)` is a bit absurd! :)
Personally, I think eliding would be a useful shorthand and if we allow it along with internal names (which I also think is a good idea) then we would want eliding to use the internal / property name.
The primary goal should be clarity at the site of the pattern. Sometimes a label adds clarity, but other times it will just add clutter. Allowing label elision ensures a reader sees a name that lines up with the meaning of the associated value with less clutter. I think this would often increase clarity. That said, it is a rather minor piece of syntactic sugar.
>
> -Joe
More information about the swift-evolution
mailing list