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

Kevin Nattinger swift at nattinger.net
Thu Dec 21 12:02:20 CST 2017


> On Dec 19, 2017, at 2:58 PM, Ted Kremenek via swift-evolution <swift-evolution at swift.org> wrote:
> 
> The review of "SE 0192 - Non-Exhaustive Enums" begins now and runs through January 3, 2018.
> 
> The proposal is available here:
> 
> https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md <https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md>
> What is your evaluation of the proposal?
> 
I was going to say -100 without future, +1 with, but other arguments on this thread have put me on the fence to mildly against, so -100 without future, -ε with.


In the proposal, there is the following text:
> The consequences of losing exhaustiveness checking for non-exhaustive enums are discussed in the "Alternatives considered" section at the end of this proposal.
> 
> A number of pre-reviewers have been concerned about the loss of exhaustiveness checking and the subsequent difficulty in updating to a new version of a dependency. In the original swift-evolution thread, Vladimir S. describes the concerning scenario <https://lists.swift.org/pipermail/swift-evolution/Week-of-Mon-20171002/040053.html> in detail.
I find it deeply disturbing that this scenario is acknowledged as "concerning" and yet ignored without justification in the proposal proper, and in the "alternatives" dismissed solely based on a baseless assumption—that the situation will be "uncommon." Even if it were an uncommon case, the negative impact is still dire enough and without a good workaround that I'd argue strongly that the concern be addressed properly.

The justification put forward to reject a `future` case is that "The expectation is that switches over non-exhaustive enums are uncommon." However, there is no evidence to support that assertion, and there are a huge number of enums in even just Apple's frameworks that people reasonably can, and in some cases really should, switch over. Go through any of the iOS frameworks and find authorization enums and delegates with enums in a callback, and you're likely to find some that it makes sense for a client to switch over. Just a few off the top of my head that I have personally switched on:

CoreBluetooth
- CBManagerState
- CBPeripheralManagerAuthorizationStatus
- CBPeripheralState
CoreLocation
- CLAuthorizationStatus
- CLActivityType
CoreData
- NSFetchedResultsChangeType
MessageUI
- MessageComposeResult
UIKit
- UITableViewCellEditingStyle

Every framework that requires user permission has its own authorization enum, many have an additional state enum, and for most delegate callbacks with an enum argument it's often a good idea to switch over the cases.

As a real-life example above and beyond the one referenced above, In the fairly small codebase I'm working in at the moment, I count a bit over 12klocs, 80-ish switches, and 6 switches that would need a `future` case (non-exhaustive, from Apple frameworks). That's about one per 2klocs, It probably wouldn't scale linearly in larger projects, but just their prevalence in the apple frameworks as I pointed out above would suggest it does grow significantly.

The extra onus on project authors required by not including a future case for those cases would make upgrading libraries and iOS versions incredibly difficult and error-prone. To ensure correctness, you would have to go over every single switch in your app, figure out the type it's switching on, and if the type is external and nonexhaustive, check that there are no new cases. Even if this is "not expected to be the common case," omitting the `future` means you have to either keep track of where all your relevant switch statements are and check them on every upgrade, go through and evaluate every switch statement to figure out whether you need to check for extra cases, or go through the API diff, find any added enum cases, and find every switch in your codebase that switches on them. All three options are dangerously error-prone and unacceptable.

In summary, failing to include a future case but requiring default instead would place an unacceptable burden on every nontrivial project every time a library is upgraded and (and I don't say this lightly) would almost certainly be the biggest mistake the Swift community has ever made.

There is an existing implementation along with the PR, so has anyone tried this change a project of significant size that uses a variety of Apple frameworks? How many `default`s did you have to put in that should be `future`, and how would you feel about having to find all those places again and any more that may be put in in a year or two *without* compiler checking?
> Is the problem being addressed significant enough to warrant a change to Swift?
> 
The problem needs to be addressed, certainly.
> Does this proposal fit well with the feel and direction of Swift?
> 
With future, sure. Without, absolutely not. As demonstrated and even acknowledged but dismissed without justification, it introduces an enormous issue with compile-time safety.
> If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?
> 
N/a
> How much effort did you put into your review? A glance, a quick reading, or an in-depth study?
> 
I kept maybe half an eye on the original thread, but read the proposal and other posts in this review thread thoroughly.
> Thanks,
> Ted Kremenek
> Review Manager
> _______________________________________________
> 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/20171221/e44d98dd/attachment.html>


More information about the swift-evolution mailing list