[swift-evolution] [Review] SE 0192 - Non-Exhaustive Enums

Xiaodi Wu xiaodi.wu at gmail.com
Fri Jan 5 00:31:14 CST 2018


On Fri, Jan 5, 2018 at 00:21 Cheyo Jimenez <cheyo at masters3d.com> wrote:

>
>
> On Jan 4, 2018, at 4:37 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>
>
> On Thu, Jan 4, 2018 at 19:29 Cheyo J. Jimenez <cheyo at masters3d.com> wrote:
>
>> On Jan 4, 2018, at 3:50 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>
>>
>> On Thu, Jan 4, 2018 at 18:39 Cheyo J. Jimenez <cheyo at masters3d.com>
>> wrote:
>>
>>>
>>> On Jan 4, 2018, at 2:55 PM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>
>>>
>>> On Thu, Jan 4, 2018 at 17:15 Cheyo J. Jimenez <cheyo at masters3d.com>
>>> wrote:
>>>
>>>> On Jan 4, 2018, at 11:53 AM, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>
>>>>
>>>> On Thu, Jan 4, 2018 at 13:46 Cheyo Jimenez <cheyo at masters3d.com> wrote:
>>>>
>>>>>
>>>>>
>>>>> On Jan 4, 2018, at 10:49 AM, Jordan Rose <jordan_rose at apple.com>
>>>>> wrote:
>>>>>
>>>>> I'll admit I hadn't thought of using "unknown default" (or "default
>>>>> unknown"). I don't think that's terrible, but I mildly prefer `unknown
>>>>> case` because it builds on the "pun" that enum elements are also defined
>>>>> using 'case'. If anything hits this part of the switch, it really will be
>>>>> an "unknown case", i.e. a statically-unknown enum element.
>>>>>
>>>>> To Cheyo's point, if this *were* to be a single token I'd probably
>>>>> spell it #unknown, like #available. Then we'd have `case #unknown:` and
>>>>> something that naturally expands to other pattern positions. I found that
>>>>> less aesthetically pleasing, though, and so a context-sensitive keyword
>>>>> seemed like the way to go.
>>>>>
>>>>> (For the record, though, I wouldn't describe `case _` as a special
>>>>> case of `default`. They do exactly the same thing, and `_` is a useful
>>>>> pattern in other contexts, so if anything the current `default` should be
>>>>> thought of as syntactic sugar for `case _`.)
>>>>>
>>>>>
>>>>> Can case _ be mixed with unknown case? How can we match all compile
>>>>> time known cases but exclude future cases?
>>>>>
>>>>
>>>> What’s your use case for that? That eliminates the possibility of
>>>> “unknown case” giving you compile-time warnings for subsequently added
>>>> cases, which was the entire purpose of adding the syntax in the first place.
>>>>
>>>>
>>>> I was thinking of a generalized `unknown case` pattern but that is out
>>>> of scope for this proposal.
>>>> <https://github.com/apple/swift-evolution/pull/777/files#diff-a68dc745ee86d09566b232b6954c5158R321>
>>>>
>>>>
>>>> switch excuse {
>>>>  case .eatenByPet :
>>>>    //…
>>>>  unknown case:
>>>>    // …
>>>>  case _:
>>>>    // …
>>>>  }
>>>>
>>>>
>>>> Should there be something like `case *` that would capture all
>>>>> currently known cases during compile time? case * and case _ would be the
>>>>> same in exhaustive enums.
>>>>>
>>>>
>>>> This is why I was suggesting another pattern that only captures known
>>>> cases at compile time:
>>>>
>>>> switch excuse {
>>>>  case .eatenByPet :
>>>>    //…
>>>>  case * : //  All cases captured at compile time.
>>>>    // …
>>>>  unknown case:
>>>>    // …
>>>>  }
>>>>
>>>
>>> Sorry, I don’t understand. However you spell it, what is your use case
>>> for this? The stated purpose of “unknown case” is to gain compile-time
>>> exhaustiveness testing, but this would not allow for that.
>>>
>>>
>>>
>>>
>>>
>>> switch (excuse, notifiedTeacherBeforeDeadline) {case (.eatenByPet, true):
>>>   // …case (.thoughtItWasDueNextWeek, true):
>>>   // …case (unknown case, true):
>>>   // …case (_, false):
>>>   // …}
>>>
>>>
>>> Im referring to the future direction section in the new PR
>>> <https://github.com/jrose-apple/swift-evolution/blob/6061c01fb4a6d742ba7213f46979c9b82891fc14/proposals/0192-non-exhaustive-enums.md#future-directions>.
>>> The above example if from there.
>>>
>>> I am fine with `unknown case` being required to be at the end of the
>>> switch for now.
>>>
>>> I think of `unknown case` as a pattern that only matches unknown cases
>>> no matter where on the switch it is.
>>>
>>> This is why I do not think that `default unknown` would work well once
>>> `unknown case` can be used a pattern.
>>>
>>> We can start a new thread on this if you’d like.
>>>
>>
>> The reason I put forward “default unknown” is precisely because the
>> proposed feature *cannot* be used in a pattern and therefore seems more apt
>> as not a case.
>>
>> It can not be used in a pattern now but you could in the future if left
>> as `case`.
>>
>>
>> It actually makes it more natural to use in the given example above
>> because “default unknown” could actually be used to provide compile-time
>> exhaustiveness checking for such a tuple pattern, whereas without being
>> able to use “unknown case” in a pattern you can’t write “case (unknown
>> case, _)”.
>>
>>
>> The way `unknown case` enforces  compile-time exhaustiveness is by only
>> matching unknown cases. The implementation may be more close to default by
>> the virtue of being forced to go at the end of the switch statement now but
>> that should not dictate the user experience.
>>
>
> We seem to agree that, by virtue of not supporting use in a pattern and
> being placed at the end, the feature is a flavor of default. I’m still not
> sure I understand why you believe it should not be a flavor of default
> going forward.
>
>
>> You still haven’t answered my question, though—what’s the use case for
>> the feature you propose?
>>
>>
>> My use case would be distinguishing between compile time known cases vs
>> “future only” cases (or unknown cases).
>>
>
> I understand that the feature you propose would allow you to make such a
> distinction, but again, what is your use case for doing so?
>
>
> Breaking out early by checking unknown cases first. I admit this is not
> deal breaker, just a different style I’d like to see supported in the
> future.
>

I'm still not sure I understand. How can the machine know that it's dealing
with an unknown case without first checking if it matches any known case?


>
> This depends on generalized `unknown case` patterns which is out of scope.
>> I am happy to talk more about this on a different thread when this proposal
>> gets approved.
>>
>>
>>
>>
>>
>>>
>>>
>>>
>>>
>>>
>>>>
>>>>>
>>>>>
>>>>> I'll add these points to the "Alternatives Considered" section in the
>>>>> PR later today.
>>>>>
>>>>> Jordan
>>>>>
>>>>>
>>>>> On Jan 3, 2018, at 22:56, Xiaodi Wu <xiaodi.wu at gmail.com> wrote:
>>>>>
>>>>> As has already been said, “case unknown” is source-breaking because it
>>>>> conflicts with any real cases named “unknown”; “\unknown” looks like a key
>>>>> path but isn’t, and I wonder if it would potentially conflict with existing
>>>>> key paths.
>>>>>
>>>>> In any case, my point was not to bikeshed the “unknown” part, but to
>>>>> ask whether any consideration had been made to have the feature presented
>>>>> as a flavor of default instead of a flavor of case.
>>>>>
>>>>> On Wed, Jan 3, 2018 at 23:57 Cheyo Jimenez <cheyo at masters3d.com>
>>>>> wrote:
>>>>>
>>>>>>
>>>>>>
>>>>>> On Jan 3, 2018, at 6:52 PM, Xiaodi Wu via swift-evolution <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>>
>>>>>> This is a very nice revision. One bikeshedding thought:
>>>>>>
>>>>>> Since "unknown case" is presented as a special kind of "default",
>>>>>> can't be mixed with "default", and can't be used in case patterns, why not
>>>>>> "default unknown" (or "unknown default") instead of "unknown case"?
>>>>>>
>>>>>>
>>>>>> `case _ :` is already a special case of default.
>>>>>> I’d rather have `case unknown :`
>>>>>> `unknown case :` is weird because of the order of `case`.
>>>>>>
>>>>>> Another alternative is `case \unknown :`
>>>>>> `\unknown` would also allow pattern matching.
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>> On Wed, Jan 3, 2018 at 8:05 PM, Jordan Rose via swift-evolution <
>>>>>> swift-evolution at swift.org> wrote:
>>>>>>
>>>>>>> On Jan 2, 2018, at 18:07, Jordan Rose <jordan_rose at apple.com> wrote:
>>>>>>>
>>>>>>> [Proposal:
>>>>>>> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
>>>>>>> ]
>>>>>>>
>>>>>>> Whew! Thanks for your feedback, everyone. On the lighter side of
>>>>>>> feedback—naming things—it seems that most people seem to like '
>>>>>>> *@frozen*', and that does in fact have the connotations we want it
>>>>>>> to have. I like it too.
>>>>>>>
>>>>>>> More seriously, this discussion has convinced me that it's worth
>>>>>>> including what the proposal discusses as a *'future' case*. The key
>>>>>>> point that swayed me is that this can produce a *warning* when the
>>>>>>> switch is missing a case rather than an *error,* which both
>>>>>>> provides the necessary compiler feedback to update your code and allows
>>>>>>> your dependencies to continue compiling when you update to a newer SDK. I
>>>>>>> know people on both sides won't be 100% satisfied with this, but does it
>>>>>>> seem like a reasonable compromise?
>>>>>>>
>>>>>>> The next question is how to spell it. I'm leaning towards
>>>>>>> `unexpected case:`, which (a) is backwards-compatible, and (b) also handles
>>>>>>> "private cases", either the fake kind that you can do in C (as described in
>>>>>>> the proposal), or some real feature we might add to Swift some day.
>>>>>>> `unknown case:` isn't bad either.
>>>>>>>
>>>>>>> I too would like to just do `unknown:` or `unexpected:` but that's
>>>>>>> technically a source-breaking change:
>>>>>>>
>>>>>>> switch foo {
>>>>>>> case bar:
>>>>>>>   unknown:
>>>>>>>   while baz() {
>>>>>>>     while garply() {
>>>>>>>       if quux() {
>>>>>>>         break unknown
>>>>>>>       }
>>>>>>>     }
>>>>>>>   }
>>>>>>> }
>>>>>>>
>>>>>>>
>>>>>>> Another downside of the `unexpected case:` spelling is that it
>>>>>>> doesn't work as part of a larger pattern. I don't have a good answer for
>>>>>>> that one, but perhaps it's acceptable for now.
>>>>>>>
>>>>>>> I'll write up a revision of the proposal soon and make sure the core
>>>>>>> team gets my recommendation when they discuss the results of the review.
>>>>>>>
>>>>>>> ---
>>>>>>>
>>>>>>> I'll respond to a few of the more intricate discussions tomorrow,
>>>>>>> including the syntax of putting a new declaration inside the enum rather
>>>>>>> than outside. Thank you again, everyone, and happy new year!
>>>>>>>
>>>>>>>
>>>>>>> I ended up doing these in the opposite order, writing up the new
>>>>>>> proposal first and not yet responding to the discussion that's further out.
>>>>>>> You can read my revisions at
>>>>>>> https://github.com/apple/swift-evolution/pull/777.
>>>>>>>
>>>>>>> In particular, I want to at least address:
>>>>>>> - Dave D and Drew C's points about versioned libraries / linking
>>>>>>> semantics of modules.
>>>>>>> - Jason M's point about migration
>>>>>>> and I'll do one more pass over the thread to see if there's anything
>>>>>>> else I didn't address directly. (That doesn't mean everyone who disagrees,
>>>>>>> just messages where I think there's more I can do to explain why the
>>>>>>> proposal is the way it is.)
>>>>>>>
>>>>>>> Jordan
>>>>>>>
>>>>>>> P.S. Enjoying the Disney references. Thanks, Nevin and Dave. :-)
>>>>>>>
>>>>>>> _______________________________________________
>>>>>>> swift-evolution mailing list
>>>>>>> swift-evolution at swift.org
>>>>>>> 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/20180105/9e6f30ee/attachment.html>


More information about the swift-evolution mailing list