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

Drew Crawford drew at sealedabstract.com
Tue Jan 2 10:07:28 CST 2018

First, this is an extremely well-written proposal, that explains itself well and tries to walk a difficult tightrope.  So, A+ for that.

That said, I think it needs modification before acceptance:

* I agree with Dave DeLong that @exhaustive does not actually "do anything", it relies on library authors to do the right thing but library authors cannot be trusted.  I am not even sure Optional will continue to have its two cases based on the track record of the swift-evolution process :-P
* I agree with Vladimir S that app developers need to be able to use compile-time checks that they handle all the "known cases" for an arbitrary enum (e.g. exhaustive or non-exhaustive), for example with "future" or some other mechanism.  Lack of testability does not actually concern me, but I feel it could be addressed by allowing the assignment of Any to a non-exhaustive enum, perhaps gated via a warning or an @testable.

I feel that a better solution to the underlying dilemma would be the following:

* As an app developer, I can use switch! or @import! to mean that I am vendoring this SDK and the runtime library will definitely be the same library I am linking against.  So it does not matter if the library author intends to someday add more cases – from my point of of view they are exhaustive, because this is the library I am linking, accept no substitutes.  Cases are checked at import time, and there is a runtime exception if somebody swaps the binary for one with "new" cases, may god have mercy on their soul
* As an app developer, in the absence of one of those opt-in mechanisms an imported enum is assumed to be open and I must handle either a default case (which is not compile-time checked for exhaustion) or a future case (which is).  I prefer "undefined" for "future" as a keyword because it seems to me library authors can also remove cases, regardless of what this proposal says.

This solution is a nod to @clattner's "the difference between source packages and binary packages that are updated outside your control (e.g. the OS, or a dynamic library that is updated independently of your app like a 3rd party plugin)."  But he is wrong that the difference is somehow tied together with a notion of binary and source: it is a difference between whether the library is vendored or nonvendored, that is whether it is shipped with the application or the OS.  If it is shipped with your application, you control the updates and so all enums can be exhaustive, if it is shipped with the OS it is updated independently and who knows what cases will appear at runtime.  But there is no law that says I have the sourcecode for all my application's libraries or that OS vendors only ship binaries, so I use "vendored" and "non-vendored", and "import-time" for "compile-time" to be precise in this distinction.

As a library author, I am not sure that the @exhaustive promise is meaningful.  Unlike resilience more generally where a library author can provide some fallback behavior for client who calls a deprecated method, there is really not much that can be done to support older clients who are unaware of my new enum case.  I suppose we could introduce compile-time checks to prevent passing that enum case to an older client, for example

public enum Foo {
    case old
    @introduced (1.1) case new

public final enum Fixed {
    case one
    @introduced (1.1) case two //error: Can't add a new case to a final enum, drop @introduced or drop final

public func bar() -> Foo {
    return .new //error: Not all clients support case new, use if #available or @available

This sort of thing might be a justification for supporting a "final" or "exhaustive" declaration, but the motivation in this listing is to support library authors within their own compilation unit, rather than exposing a signal to app developers that may or may not be reliable moving forward.

As shown in this listing, I find "final" more natural and more in the spirit of Swift than @exhaustive.


On December 19, 2017 at 4:58:14 PM, Ted Kremenek (kremenek at apple.com) wrote:

The review of "SE 0192 - Non-Exhaustive Enums" begins now and runs through January 3, 2018.

The proposal is available here:

Reviews are an important part of the Swift evolution process. All review feedback should be sent to the swift-evolution mailing list at:

or, if you would like to keep your feedback private, directly to the review manager. 

When replying, please try to keep the proposal link at the top of the message:

Proposal link: https://github.com/apple/swift-evolution/blob/master/proposals/0192-non-exhaustive-enums.md
Reply text
Other replies
What goes into a review of a proposal?

The goal of the review process is to improve the proposal under review through constructive criticism and, eventually, determine the direction of Swift. 

When reviewing a proposal, here are some questions to consider:

What is your evaluation of the proposal?

Is the problem being addressed significant enough to warrant a change to Swift?

Does this proposal fit well with the feel and direction of Swift?

If you have used other languages or libraries with a similar feature, how do you feel that this proposal compares to those?

How much effort did you put into your review? A glance, a quick reading, or an in-depth study?

Ted Kremenek
Review Manager
swift-evolution-announce mailing list
swift-evolution-announce at swift.org
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://lists.swift.org/pipermail/swift-evolution/attachments/20180102/19c2d6ee/attachment.html>

More information about the swift-evolution mailing list