Enums and Source Compatibility

Ah, I get it now. Even if the switch knows what to do with the unknown value, the rest of your code would have to know what to do with it, and that is unlikely.

-Kenny

···

On Sep 18, 2017, at 10:23 AM, Jordan Rose <jordan_rose@apple.com> wrote:

On Sep 16, 2017, at 15:35, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has been added to an enum, since I may have to do something about it. How about adding the “exhaustive” keyword to be used in the switch statement? Like

exhaustive switch excuse {
    case eatenByPet:
        // …
    case thoughtItWasDueNextWeek:
        // …
    default:
        // …
}

If exhaustive is used, there would be a warning if all cases aren’t covered *even though default exists*. This means that I as the client thought I had everything covered when I wrote this code.

As already mentioned, this makes the default case un-testable, which brings me to

2) All non-exhaustive enums should have the pseudo value “default” that can be used just like a regular value. This would allow you to write code like:

teacher.failedToHandInHomework(excuse: .default)

which would allow you to trip the default case in any code you may write.

Brent came up with this idea as well, but after thinking it through Joe Groff and I found that it doesn't really work in practice:

It’s going to be very common to have a future value and hand it right back to the framework without looking at it, for example:

override func process(_ transaction: @testable Transaction) {
  switch transaction {
  case .deposit(let amount):
    // …
  case .withdrawal(let amount):
    // …
  default:
    super.process(transaction) // hmm…
  }
}

So just making it to the ‘default’ case doesn’t guarantee that it’s testable in practice.

I'll add the actual code here to the "Testing invalid cases" section under "Alternatives considered", since that's a clearer example than the paragraph I wrote. (Oh, and the "exhaustive switch" is equivalent to the section on "'future' cases".)

Thanks for the feedback!
Jordan

That's pretty much the same as this proposal except you don't have the new keyword. I'm not sure why that really makes a difference, since they're obviously paired, and it would limit existing libraries from declaring exhaustive enums until they've moved entirely to Swift 5 mode. I think the current proposal makes sense as is.

The difference is that it reduces the keyword soup and removes a keyword that will be the default behavior enums have in Swift 5. If we follow the same reasoning, why don’t we have nonfinal, @nonescaping, @nonDiscardableResult? Is it really worth adding a keyword only to support libraries while they transition to Swift 5?

···

On 18 Sep 2017, at 19:20, Jordan Rose <jordan_rose@apple.com> wrote:

Jordan

On Sep 16, 2017, at 01:55, David Hart <david@hartbit.com> wrote:

I’m still very much bothered by having 2 new keywords. I would really prefer the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I'd like to discuss a processing of nonexhaustive external enums(imported from separate module/framework) a little more.

I understand that we (in most cases) don't want to exhaustively check some C's declared enum which is used for some system's API etc.
But what about 'usual' libraries distributed as framework/module?

Do you agree that:

1. In most cases external enums(public enums declared in *separate module*) will be nonexhaustive, because library developer don't want to crash consumer's code if later will be decided that one more enum case is needed in that public enum.
Enums like Optional<T>, that should be exhaustive, will be rare in compare to "usual" enums like ButtonType, PaymentMethod, LoginKind etc

2. So, almost any enum coming from separate module/framework, even if library designer *wants* user's code to process that enum exhaustive(and it is perfectly logically to process it exhaustively in some places of user's code), will be declared as 'nonexhaustive' *just* to preserve binary compatibility if new case will be added.

3. So we actually will lose a compiler's help to work with most of such external enums.

4. If you ever need to support a code with exhaustive switch regarding external 'nonexhaustive' enum(and as noted above, most of such enums will be nonexhaustive) - you are in a big trouble, you'll need to manually check for each newer version of used library(module) if there are new cases in used enums for each switch in your code, or try to find a 3rd party tools that will help with this. But given you have 'default' in your switch - how the tool can say that you want tot be exhaustive here?

?

Also, please consider the two examples below. Is there incorrect logic/assumption used in any of them?

1. Let's say I have a Shapes enum in my library, which is distributes as separate module/framework. Each shape will have its own properties(like radius for .circle, side length for .square, angle and lengths for .line etc). Will I defined it as 'exhaustive' ? No. It is very possible, that I'll add some cases into the enum and I don't want to break user's code. Is it possible that user's code want to switch exhaustive on this enum? Of course, but there is no support for this in compiler.
Can user's code work with new(future) enums? It depends, but *this is possible*, for example it can process only known cases, and show some warning like "unknown items found, please update to latest version of app" instead of crash.

2.
* I'm using a framework(separate module) that exports Things enum.
* This framework provides user's code with [Things] array
* I show each 'thing'(let's say its 'title' property) from that array in TableView per row
* By selecting a row, I show a details page for selected thing. Information on details page depends on associated value for the selected 'thing'
* For unsupported(future) 'things' I'll show only title for it in TableView and 'Unsupported' marker. Details page will not be available for it, until I update the program. When selecting it, alert will show something like "Unknown type of thing. Please update the app to support new things".
* Is it required for me to be able to exhaustive switch of such enum? Yes, I need this to process all known cases in Details page. Exactly why we need exhaustive switch for 'internal' enums. But no compiler's help in this case.

I just want to say, if I understand correctly, that enum declared in separate module/framework will usually be 'nonexhaustive' even if library developer expects user's code to exhaustive switch on that enum. And that we really need a way to be exhaustive in switch in our code regarding imported enum which is declared as 'nonexhaustive' in its module.

Thank you for attention and your time.
Vladimir.

···

On 18.09.2017 20:23, Jordan Rose via swift-evolution wrote:

On Sep 16, 2017, at 15:35, Kenny Leung via swift-evolution >> <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has been added to an enum, since I may have to do something about it. How about adding the “exhaustive” keyword to be used in the switch statement? Like

exhaustive switch excuse {
    case eatenByPet:
        // …
    case thoughtItWasDueNextWeek:
        // …
    default:
        // …
}

If exhaustive is used, there would be a warning if all cases aren’t covered *even though default exists*. This means that I as the client thought I had everything covered when I wrote this code.

As already mentioned, this makes the default case un-testable, which brings me to

2) All non-exhaustive enums should have the pseudo value “default” that can be used just like a regular value. This would allow you to write code like:

teacher.failedToHandInHomework(excuse: .default)

which would allow you to trip the default case in any code you may write.

Brent came up with this idea as well, but after thinking it through Joe Groff and I found that it doesn't really work in practice:

It’s going to be very common to have a future value and hand it right back to the framework without looking at it, for example:

    override func process(_ transaction: @testable Transaction) {
      switch transaction {
      case .deposit(let amount):
        // …
      case .withdrawal(let amount):
        // …
      default:
        super.process(transaction) // hmm…
      }
    }

So just making it to the ‘default’ case doesn’t guarantee that it’s testable in practice.

I'll add the actual code here to the "Testing invalid cases" section under "Alternatives considered", since that's a clearer example than the paragraph I wrote. (Oh, and the "exhaustive switch" is equivalent to the section on "'future' cases".)

Thanks for the feedback!
Jordan

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

I run into use cases like this all the time…

I think I would prefer to see those concrete cases in a subtype though:

  enum DrinkSize {
    case small
    case medium
    case large
  }

  enum SummerDrinkSize : DrinkSize {
    //Inherits DrinkSize’s cases
    case extraLarge
  }

Because it is a subtype, you could place a SummerDrinkSize anywhere you can put a DrinkSize. As a result, all switches on it would need a default case to handle cases they hadn’t planned for. If you mark an enum with “final” then it can’t be extended and switches can be exhaustive.

You have the subtype relationship backwards here. DrinkSize is a subtype of SummerDrinkSize. All values of DrinkSize are also valid values of SummerDrinkSize but not vice versa. For this reason, inheritance syntax doesn't make sense. The syntax that makes more sense is some kind of case embedding syntax:

enum SummerDrinkSize {
    cases DrinkSize
    case extraLarge
}

In addition to inheriting the cases, a subtype would also inherit, and be able to override, methods defined on the super-type. You could use super to call the super-type’s implementation.

I think implementation sharing is a bad idea for value types. Value subtyping should be conceptualized as a restricted mechanism for value-preserving implicit conversion.

···

Sent from my iPad

On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote:

It is a bigger overhaul, but I think it actually ends up being semantically simpler for the end user. Basically, you can do the same types of things you can with classes... with the same syntax (just without the reference-type-ness).

It just so happens that this would also solve the problem of adding cases to (non-final) library enums, because switches of the enums would need to handle default/unexpected cases. That is a very abstract/confusing problem for end users who don’t write libraries to understand though. I think it is much easier to explain “final” as being the same as it is in classes, in that it prevents subclassing… which means you know what all the cases are.

More work (also more powerful), but semantically simpler. It just combines concepts we already know...

Thanks,
Jon

On Sep 16, 2017, at 3:51 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

Oops, forgot something:

"Can there be a kind of open enum where you can add new cases in extensions?”

I have a use case for this. I’m trying to write a database ORM with abstract API and concrete instances for different database. So I have defined:

open class Database {
   init(connectionDictionary: [ConnectionDictionaryKey:String]) {
        self.connectionDictionary = connectionDictionary;
    }
}

Where I have ConnectionDictionaryKey defined as an enum, with values like .hostName, .databaseName, .userName, .password, .databaseName, etc…

But concrete databases may have other options that need to be added to the connection dictionary. It would be nice if they could just extend ConnectionDictionaryKey with new cases.

-Kenny

On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org> wrote:

In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has been added to an enum, since I may have to do something about it. How about adding the “exhaustive” keyword to be used in the switch statement? Like

exhaustive switch excuse {
    case eatenByPet:
        // …
    case thoughtItWasDueNextWeek:
        // …
    default:
        // …
}

If exhaustive is used, there would be a warning if all cases aren’t covered *even though default exists*. This means that I as the client thought I had everything covered when I wrote this code.

As already mentioned, this makes the default case un-testable, which brings me to

2) All non-exhaustive enums should have the pseudo value “default” that can be used just like a regular value. This would allow you to write code like:

teacher.failedToHandInHomework(excuse: .default)

which would allow you to trip the default case in any code you may write.

-Kenny

On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

If a library writer can’t remember to declare non-exhaustive enums as such, they probably will forget many more important aspects of creating a library. They probably should not be writing libraries. Arguments like this make sense on the surface, but creating libraries involves hundreds or thousands of decisions. I wish you luck in making that process idiot proof. A library linter could easily warn that exposed enums are exhaustive. The exhaustive keyword should be optional to make the decision obvious and suppress warnings. Complicating the user experience in a vain attempt to make “expert" coding safer is misguided.

I think the same logic goes both ways: If a library author can’t remember to declare exhaustive enums as such, they will probably forget many more important aspects of creating a library.

The problem here is fundamental: Exhaustive is a guarantee. A guarantee should require action. Non-Exhaustive guarantees nothing. It makes you safer. That is all.

1) Exhaustive enums are inherently better: they allow a developer to know that they have covered all possible cases by not using a default.
2) This proposal forces developers to add a keyword to get this behavior in their apps, which is common to all other languages with enums that I have used. This proposal breaks the model common to all (?) current implementations of enums.

This may be a little harsh, but there don’t seem to be many advocates for novice and “ordinary” application developers on this list. That is not unexpected given the number of extremely knowledgeable compiler and library developers on this list (for whom I have the highest respect). I believe that there are more creative (and probably more difficult to build) possible solutions to some of the tough problems in Swift’s future. In that spirit, see below.

I personally am an “ordinary” application developer.

I think the issue here is that everyone is seeing Swift as *they* intend to use it. For App Devs, exhaustive switches are nice, which means they really are fighting tooth and nail to keep them. I understand that. But I’m also trying to keep my mind open for “what happens to an app I compiled in iOS 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple or any other library author to be completely knowledgable about every case in the future, and to audit every line of code and manually give non-exhaustive.

Why do people want “exhaustive” to be the default?
Because we like things as they are.

No, because it makes sense to make common things easy and uncommon things possible.

Because we like not having to consider edge cases. Because we want to imagine that will give framework developers the control to make our lives difficult because they’ll just be lazy and make our lives hard by not annotating. And this certainly is a concern. But I think a larger concern is breaking apps left, right and centre, or not being able to extend frameworks because an earlier developer on a project made an oversight.

This happens all the time: Apple deprecates APIs and asked developers to use new ones. If a library writer does not run (the as-yet hypothetical ) library lint, not participate in thorough code reviews,…, they can simply create a new non-exhaustive enum and deprecate the old one. Yes, there will be some redundant function calls for a while, but again, similar things happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly reviewed. It is not the end of the world to deprecate and migrate APIs. You may remember garbage collected Objective-C, the change that “viewWillAppear” suddenly was not called when it used to be in iOS. We all survived the elimination of GC and moving our view initialization code. Libraries and developers can survive mistakes and improvements.

ABI stability does not require foolproof, immutable, ABIs. In essence, it is just a guarantee that the build system won’t require rebuilds if library source code stays the same, or is added to, not that applications will never have to be rebuilt in the real world where breaking changes are often required. Adding ABI stability when enums change (in limited ways, don’t forget, removing a case is a breaking change) is a good addition, but it does not rise to the level of requiring degradation of the experience for beginners, IMO.

Its in everyone’s best interest to think before we put handcuffs on, no matter how painful that is. Even if that means you make apps where you just write “default: fatalError(“I don’t handle unreachable defaults”)"

And lets be clear: Swift isn’t an app development language. It also isn’t a framework development language. It’s a multipurpose language designed to Take Over The World™. This means we need to think holistically about what is better for everyone. Not just ourselves.

That includes being easy to learn and understand. Enums are exhaustive in other languages and should be exhaustive by default in Swift. No extra keywords should be required to create “MyFirstEnum” that behaves in a sensible way. The documentation that describes why you need to write a ‘default’ clause or 'exhaustive' when you have all the possible cases written down should be interesting. May I suggest: “You see, if you write a library (don’t worry about what that means right now) you don’t have to worry about being not very good at it. If and when you write one, it will be a tiny bit easier, so write this meaningless clause or the magical keyword — your choice.”

If you declare it is exhaustive and it was an oversight, and then realise after the fact that you are wrong, you have to open it up. This will break third party apps. It will be disallowed by the ABI compatibility requirements.

If you declare it isn’t exhaustive due to an oversight (or perhaps you’re just not sure yet), and then realise after the fact it is exhaustive, you can close it up. This will not break third party apps. It will also be allowed for ABI compatibility.

This benefits everyone. Make library owners choose a guarantee, rather than be defaulted into it. Much like they have to declare choose to declare “final” on a class: you can’t retroactively reneg that promise: it will break everyone who assumed it to be the case!

It does not benefit the creation of 90+% of enums. It is one more arcane rule for the vast majority of developers.

The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding not included) switch that could be enabled by default for library targets and disabled by default for “application” targets. The switch would make not explicitly specifying exhaustiveness an error or warning when enabled. Perhaps this could be combined with other options that would tailor the development experience for library/application developers. This would help avoid “zero-sum” choices between benefitting library or application developers in the future.

The Swift team have fundamentally opposed such pushes for “compiler modes” for a long time. I don’t expect they will embrace them now, nor do I think they should just to avoid us devs having to write the occasional “default” clause. This is, to be clear, a relatively rare case.

It is probably a good choice, but there are potential upsides. Oh, course, this could easily lead to a library dialect and an application dialect of Swift. That is already the de-facto state of affairs for many languages, including Swift. Would formalizing the difference make of “taking over the world” more attainable or just create a mess? A "library switch" could be horribly abused, and should only be used as a last resort. Ideally, it would only generate warnings in library mode.

···

On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:

On 17 Sep 2017, at 4:35 am, Christopher Kornher <ckornher@me.com <mailto:ckornher@me.com>> wrote:

On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Xcode and the SPM should be able to distinguish between the target types and generate the proper defaults. I do not believe that this is too mysterious for developers. There would be learning step for developers wiring their first library, but that is not necessarily a bad thing since creating a reusable library requires a different mindset than creating an application.

Exhaustive and open by default with keywords to close things down if the framework author wants them.

Sent from my iPhone

On 16 Sep 2017, at 09:55, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’m still very much bothered by having 2 new keywords. I would really prefer the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Please note that, as proposed, enums are always treated as exhaustive *within the same module*. A new user writing MyFirstEnum is likely using it within the same module, and will thus get exhaustive behavior with no extra keywords required.

-BJ

···

On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution <swift-evolution@swift.org> wrote:

On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:

On 17 Sep 2017, at 4:35 am, Christopher Kornher <ckornher@me.com> wrote:

On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org> wrote:

If a library writer can’t remember to declare non-exhaustive enums as such, they probably will forget many more important aspects of creating a library. They probably should not be writing libraries. Arguments like this make sense on the surface, but creating libraries involves hundreds or thousands of decisions. I wish you luck in making that process idiot proof. A library linter could easily warn that exposed enums are exhaustive. The exhaustive keyword should be optional to make the decision obvious and suppress warnings. Complicating the user experience in a vain attempt to make “expert" coding safer is misguided.

I think the same logic goes both ways: If a library author can’t remember to declare exhaustive enums as such, they will probably forget many more important aspects of creating a library.

The problem here is fundamental: Exhaustive is a guarantee. A guarantee should require action. Non-Exhaustive guarantees nothing. It makes you safer. That is all.

1) Exhaustive enums are inherently better: they allow a developer to know that they have covered all possible cases by not using a default.
2) This proposal forces developers to add a keyword to get this behavior in their apps, which is common to all other languages with enums that I have used. This proposal breaks the model common to all (?) current implementations of enums.

This may be a little harsh, but there don’t seem to be many advocates for novice and “ordinary” application developers on this list. That is not unexpected given the number of extremely knowledgeable compiler and library developers on this list (for whom I have the highest respect). I believe that there are more creative (and probably more difficult to build) possible solutions to some of the tough problems in Swift’s future. In that spirit, see below.

I personally am an “ordinary” application developer.

I think the issue here is that everyone is seeing Swift as *they* intend to use it. For App Devs, exhaustive switches are nice, which means they really are fighting tooth and nail to keep them. I understand that. But I’m also trying to keep my mind open for “what happens to an app I compiled in iOS 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple or any other library author to be completely knowledgable about every case in the future, and to audit every line of code and manually give non-exhaustive.

Why do people want “exhaustive” to be the default?
Because we like things as they are.

No, because it makes sense to make common things easy and uncommon things possible.

Because we like not having to consider edge cases. Because we want to imagine that will give framework developers the control to make our lives difficult because they’ll just be lazy and make our lives hard by not annotating. And this certainly is a concern. But I think a larger concern is breaking apps left, right and centre, or not being able to extend frameworks because an earlier developer on a project made an oversight.

This happens all the time: Apple deprecates APIs and asked developers to use new ones. If a library writer does not run (the as-yet hypothetical ) library lint, not participate in thorough code reviews,…, they can simply create a new non-exhaustive enum and deprecate the old one. Yes, there will be some redundant function calls for a while, but again, similar things happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly reviewed. It is not the end of the world to deprecate and migrate APIs. You may remember garbage collected Objective-C, the change that “viewWillAppear” suddenly was not called when it used to be in iOS. We all survived the elimination of GC and moving our view initialization code. Libraries and developers can survive mistakes and improvements.

ABI stability does not require foolproof, immutable, ABIs. In essence, it is just a guarantee that the build system won’t require rebuilds if library source code stays the same, or is added to, not that applications will never have to be rebuilt in the real world where breaking changes are often required. Adding ABI stability when enums change (in limited ways, don’t forget, removing a case is a breaking change) is a good addition, but it does not rise to the level of requiring degradation of the experience for beginners, IMO.

Its in everyone’s best interest to think before we put handcuffs on, no matter how painful that is. Even if that means you make apps where you just write “default: fatalError(“I don’t handle unreachable defaults”)"

And lets be clear: Swift isn’t an app development language. It also isn’t a framework development language. It’s a multipurpose language designed to Take Over The World™. This means we need to think holistically about what is better for everyone. Not just ourselves.

That includes being easy to learn and understand. Enums are exhaustive in other languages and should be exhaustive by default in Swift. No extra keywords should be required to create “MyFirstEnum” that behaves in a sensible way. The documentation that describes why you need to write a ‘default’ clause or 'exhaustive' when you have all the possible cases written down should be interesting. May I suggest: “You see, if you write a library (don’t worry about what that means right now) you don’t have to worry about being not very good at it. If and when you write one, it will be a tiny bit easier, so write this meaningless clause or the magical keyword — your choice.”

If you declare it is exhaustive and it was an oversight, and then realise after the fact that you are wrong, you have to open it up. This will break third party apps. It will be disallowed by the ABI compatibility requirements.

If you declare it isn’t exhaustive due to an oversight (or perhaps you’re just not sure yet), and then realise after the fact it is exhaustive, you can close it up. This will not break third party apps. It will also be allowed for ABI compatibility.

This benefits everyone. Make library owners choose a guarantee, rather than be defaulted into it. Much like they have to declare choose to declare “final” on a class: you can’t retroactively reneg that promise: it will break everyone who assumed it to be the case!

It does not benefit the creation of 90+% of enums. It is one more arcane rule for the vast majority of developers.

The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding not included) switch that could be enabled by default for library targets and disabled by default for “application” targets. The switch would make not explicitly specifying exhaustiveness an error or warning when enabled. Perhaps this could be combined with other options that would tailor the development experience for library/application developers. This would help avoid “zero-sum” choices between benefitting library or application developers in the future.

The Swift team have fundamentally opposed such pushes for “compiler modes” for a long time. I don’t expect they will embrace them now, nor do I think they should just to avoid us devs having to write the occasional “default” clause. This is, to be clear, a relatively rare case.

It is probably a good choice, but there are potential upsides. Oh, course, this could easily lead to a library dialect and an application dialect of Swift. That is already the de-facto state of affairs for many languages, including Swift. Would formalizing the difference make of “taking over the world” more attainable or just create a mess? A "library switch" could be horribly abused, and should only be used as a last resort. Ideally, it would only generate warnings in library mode.

Xcode and the SPM should be able to distinguish between the target types and generate the proper defaults. I do not believe that this is too mysterious for developers. There would be learning step for developers wiring their first library, but that is not necessarily a bad thing since creating a reusable library requires a different mindset than creating an application.

Exhaustive and open by default with keywords to close things down if the framework author wants them.

Sent from my iPhone

On 16 Sep 2017, at 09:55, David Hart via swift-evolution <swift-evolution@swift.org> wrote:

I’m still very much bothered by having 2 new keywords. I would really prefer the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Ah, ok. I had missed this too, somehow.

···

On Sep 17, 2017, at 4:04 PM, BJ Homer via swift-evolution <swift-evolution@swift.org> wrote:

Please note that, as proposed, enums are always treated as exhaustive *within the same module*. A new user writing MyFirstEnum is likely using it within the same module, and will thus get exhaustive behavior with no extra keywords required.

-BJ

On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 17 Sep 2017, at 4:35 am, Christopher Kornher <ckornher@me.com <mailto:ckornher@me.com>> wrote:

On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If a library writer can’t remember to declare non-exhaustive enums as such, they probably will forget many more important aspects of creating a library. They probably should not be writing libraries. Arguments like this make sense on the surface, but creating libraries involves hundreds or thousands of decisions. I wish you luck in making that process idiot proof. A library linter could easily warn that exposed enums are exhaustive. The exhaustive keyword should be optional to make the decision obvious and suppress warnings. Complicating the user experience in a vain attempt to make “expert" coding safer is misguided.

I think the same logic goes both ways: If a library author can’t remember to declare exhaustive enums as such, they will probably forget many more important aspects of creating a library.

The problem here is fundamental: Exhaustive is a guarantee. A guarantee should require action. Non-Exhaustive guarantees nothing. It makes you safer. That is all.

1) Exhaustive enums are inherently better: they allow a developer to know that they have covered all possible cases by not using a default.
2) This proposal forces developers to add a keyword to get this behavior in their apps, which is common to all other languages with enums that I have used. This proposal breaks the model common to all (?) current implementations of enums.

This may be a little harsh, but there don’t seem to be many advocates for novice and “ordinary” application developers on this list. That is not unexpected given the number of extremely knowledgeable compiler and library developers on this list (for whom I have the highest respect). I believe that there are more creative (and probably more difficult to build) possible solutions to some of the tough problems in Swift’s future. In that spirit, see below.

I personally am an “ordinary” application developer.

I think the issue here is that everyone is seeing Swift as *they* intend to use it. For App Devs, exhaustive switches are nice, which means they really are fighting tooth and nail to keep them. I understand that. But I’m also trying to keep my mind open for “what happens to an app I compiled in iOS 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple or any other library author to be completely knowledgable about every case in the future, and to audit every line of code and manually give non-exhaustive.

Why do people want “exhaustive” to be the default?
Because we like things as they are.

No, because it makes sense to make common things easy and uncommon things possible.

Because we like not having to consider edge cases. Because we want to imagine that will give framework developers the control to make our lives difficult because they’ll just be lazy and make our lives hard by not annotating. And this certainly is a concern. But I think a larger concern is breaking apps left, right and centre, or not being able to extend frameworks because an earlier developer on a project made an oversight.

This happens all the time: Apple deprecates APIs and asked developers to use new ones. If a library writer does not run (the as-yet hypothetical ) library lint, not participate in thorough code reviews,…, they can simply create a new non-exhaustive enum and deprecate the old one. Yes, there will be some redundant function calls for a while, but again, similar things happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly reviewed. It is not the end of the world to deprecate and migrate APIs. You may remember garbage collected Objective-C, the change that “viewWillAppear” suddenly was not called when it used to be in iOS. We all survived the elimination of GC and moving our view initialization code. Libraries and developers can survive mistakes and improvements.

ABI stability does not require foolproof, immutable, ABIs. In essence, it is just a guarantee that the build system won’t require rebuilds if library source code stays the same, or is added to, not that applications will never have to be rebuilt in the real world where breaking changes are often required. Adding ABI stability when enums change (in limited ways, don’t forget, removing a case is a breaking change) is a good addition, but it does not rise to the level of requiring degradation of the experience for beginners, IMO.

Its in everyone’s best interest to think before we put handcuffs on, no matter how painful that is. Even if that means you make apps where you just write “default: fatalError(“I don’t handle unreachable defaults”)"

And lets be clear: Swift isn’t an app development language. It also isn’t a framework development language. It’s a multipurpose language designed to Take Over The World™. This means we need to think holistically about what is better for everyone. Not just ourselves.

That includes being easy to learn and understand. Enums are exhaustive in other languages and should be exhaustive by default in Swift. No extra keywords should be required to create “MyFirstEnum” that behaves in a sensible way. The documentation that describes why you need to write a ‘default’ clause or 'exhaustive' when you have all the possible cases written down should be interesting. May I suggest: “You see, if you write a library (don’t worry about what that means right now) you don’t have to worry about being not very good at it. If and when you write one, it will be a tiny bit easier, so write this meaningless clause or the magical keyword — your choice.”

If you declare it is exhaustive and it was an oversight, and then realise after the fact that you are wrong, you have to open it up. This will break third party apps. It will be disallowed by the ABI compatibility requirements.

If you declare it isn’t exhaustive due to an oversight (or perhaps you’re just not sure yet), and then realise after the fact it is exhaustive, you can close it up. This will not break third party apps. It will also be allowed for ABI compatibility.

This benefits everyone. Make library owners choose a guarantee, rather than be defaulted into it. Much like they have to declare choose to declare “final” on a class: you can’t retroactively reneg that promise: it will break everyone who assumed it to be the case!

It does not benefit the creation of 90+% of enums. It is one more arcane rule for the vast majority of developers.

The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding not included) switch that could be enabled by default for library targets and disabled by default for “application” targets. The switch would make not explicitly specifying exhaustiveness an error or warning when enabled. Perhaps this could be combined with other options that would tailor the development experience for library/application developers. This would help avoid “zero-sum” choices between benefitting library or application developers in the future.

The Swift team have fundamentally opposed such pushes for “compiler modes” for a long time. I don’t expect they will embrace them now, nor do I think they should just to avoid us devs having to write the occasional “default” clause. This is, to be clear, a relatively rare case.

It is probably a good choice, but there are potential upsides. Oh, course, this could easily lead to a library dialect and an application dialect of Swift. That is already the de-facto state of affairs for many languages, including Swift. Would formalizing the difference make of “taking over the world” more attainable or just create a mess? A "library switch" could be horribly abused, and should only be used as a last resort. Ideally, it would only generate warnings in library mode.

Xcode and the SPM should be able to distinguish between the target types and generate the proper defaults. I do not believe that this is too mysterious for developers. There would be learning step for developers wiring their first library, but that is not necessarily a bad thing since creating a reusable library requires a different mindset than creating an application.

Exhaustive and open by default with keywords to close things down if the framework author wants them.

Sent from my iPhone

On 16 Sep 2017, at 09:55, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’m still very much bothered by having 2 new keywords. I would really prefer the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Please note that, as proposed, enums are always treated as exhaustive *within the same module*. A new user writing MyFirstEnum is likely using it within the same module, and will thus get exhaustive behavior with no extra keywords required.

• What is your evaluation of the proposal?
  Uh, +1

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

Apologies for wasting everyone’s time...

···

On Sep 17, 2017, at 5:04 PM, BJ Homer <bjhomer@gmail.com> wrote:
  
-BJ

On Sep 17, 2017, at 3:20 PM, Christopher Kornher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On Sep 17, 2017, at 6:33 AM, Rod Brown via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

On 17 Sep 2017, at 4:35 am, Christopher Kornher <ckornher@me.com <mailto:ckornher@me.com>> wrote:

On Sep 16, 2017, at 11:28 AM, Christopher Kornher via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

If a library writer can’t remember to declare non-exhaustive enums as such, they probably will forget many more important aspects of creating a library. They probably should not be writing libraries. Arguments like this make sense on the surface, but creating libraries involves hundreds or thousands of decisions. I wish you luck in making that process idiot proof. A library linter could easily warn that exposed enums are exhaustive. The exhaustive keyword should be optional to make the decision obvious and suppress warnings. Complicating the user experience in a vain attempt to make “expert" coding safer is misguided.

I think the same logic goes both ways: If a library author can’t remember to declare exhaustive enums as such, they will probably forget many more important aspects of creating a library.

The problem here is fundamental: Exhaustive is a guarantee. A guarantee should require action. Non-Exhaustive guarantees nothing. It makes you safer. That is all.

1) Exhaustive enums are inherently better: they allow a developer to know that they have covered all possible cases by not using a default.
2) This proposal forces developers to add a keyword to get this behavior in their apps, which is common to all other languages with enums that I have used. This proposal breaks the model common to all (?) current implementations of enums.

This may be a little harsh, but there don’t seem to be many advocates for novice and “ordinary” application developers on this list. That is not unexpected given the number of extremely knowledgeable compiler and library developers on this list (for whom I have the highest respect). I believe that there are more creative (and probably more difficult to build) possible solutions to some of the tough problems in Swift’s future. In that spirit, see below.

I personally am an “ordinary” application developer.

I think the issue here is that everyone is seeing Swift as *they* intend to use it. For App Devs, exhaustive switches are nice, which means they really are fighting tooth and nail to keep them. I understand that. But I’m also trying to keep my mind open for “what happens to an app I compiled in iOS 15 that I compiled for iOS 11?” And this gives me pause. I can’t ask Apple or any other library author to be completely knowledgable about every case in the future, and to audit every line of code and manually give non-exhaustive.

Why do people want “exhaustive” to be the default?
Because we like things as they are.

No, because it makes sense to make common things easy and uncommon things possible.

Because we like not having to consider edge cases. Because we want to imagine that will give framework developers the control to make our lives difficult because they’ll just be lazy and make our lives hard by not annotating. And this certainly is a concern. But I think a larger concern is breaking apps left, right and centre, or not being able to extend frameworks because an earlier developer on a project made an oversight.

This happens all the time: Apple deprecates APIs and asked developers to use new ones. If a library writer does not run (the as-yet hypothetical ) library lint, not participate in thorough code reviews,…, they can simply create a new non-exhaustive enum and deprecate the old one. Yes, there will be some redundant function calls for a while, but again, similar things happen, even in APIs like Apple’s, that (one hopes, at least) are thoroughly reviewed. It is not the end of the world to deprecate and migrate APIs. You may remember garbage collected Objective-C, the change that “viewWillAppear” suddenly was not called when it used to be in iOS. We all survived the elimination of GC and moving our view initialization code. Libraries and developers can survive mistakes and improvements.

ABI stability does not require foolproof, immutable, ABIs. In essence, it is just a guarantee that the build system won’t require rebuilds if library source code stays the same, or is added to, not that applications will never have to be rebuilt in the real world where breaking changes are often required. Adding ABI stability when enums change (in limited ways, don’t forget, removing a case is a breaking change) is a good addition, but it does not rise to the level of requiring degradation of the experience for beginners, IMO.

Its in everyone’s best interest to think before we put handcuffs on, no matter how painful that is. Even if that means you make apps where you just write “default: fatalError(“I don’t handle unreachable defaults”)"

And lets be clear: Swift isn’t an app development language. It also isn’t a framework development language. It’s a multipurpose language designed to Take Over The World™. This means we need to think holistically about what is better for everyone. Not just ourselves.

That includes being easy to learn and understand. Enums are exhaustive in other languages and should be exhaustive by default in Swift. No extra keywords should be required to create “MyFirstEnum” that behaves in a sensible way. The documentation that describes why you need to write a ‘default’ clause or 'exhaustive' when you have all the possible cases written down should be interesting. May I suggest: “You see, if you write a library (don’t worry about what that means right now) you don’t have to worry about being not very good at it. If and when you write one, it will be a tiny bit easier, so write this meaningless clause or the magical keyword — your choice.”

If you declare it is exhaustive and it was an oversight, and then realise after the fact that you are wrong, you have to open it up. This will break third party apps. It will be disallowed by the ABI compatibility requirements.

If you declare it isn’t exhaustive due to an oversight (or perhaps you’re just not sure yet), and then realise after the fact it is exhaustive, you can close it up. This will not break third party apps. It will also be allowed for ABI compatibility.

This benefits everyone. Make library owners choose a guarantee, rather than be defaulted into it. Much like they have to declare choose to declare “final” on a class: you can’t retroactively reneg that promise: it will break everyone who assumed it to be the case!

It does not benefit the creation of 90+% of enums. It is one more arcane rule for the vast majority of developers.

The Swift compiler could offer a “strict enum exhaustiveness” (bikeshedding not included) switch that could be enabled by default for library targets and disabled by default for “application” targets. The switch would make not explicitly specifying exhaustiveness an error or warning when enabled. Perhaps this could be combined with other options that would tailor the development experience for library/application developers. This would help avoid “zero-sum” choices between benefitting library or application developers in the future.

The Swift team have fundamentally opposed such pushes for “compiler modes” for a long time. I don’t expect they will embrace them now, nor do I think they should just to avoid us devs having to write the occasional “default” clause. This is, to be clear, a relatively rare case.

It is probably a good choice, but there are potential upsides. Oh, course, this could easily lead to a library dialect and an application dialect of Swift. That is already the de-facto state of affairs for many languages, including Swift. Would formalizing the difference make of “taking over the world” more attainable or just create a mess? A "library switch" could be horribly abused, and should only be used as a last resort. Ideally, it would only generate warnings in library mode.

Xcode and the SPM should be able to distinguish between the target types and generate the proper defaults. I do not believe that this is too mysterious for developers. There would be learning step for developers wiring their first library, but that is not necessarily a bad thing since creating a reusable library requires a different mindset than creating an application.

Exhaustive and open by default with keywords to close things down if the framework author wants them.

Sent from my iPhone

On 16 Sep 2017, at 09:55, David Hart via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I’m still very much bothered by having 2 new keywords. I would really prefer the following plan:

Exhaustive by default in Swift 4
No new keyword in Swift 4 to change that behaviour
Non-exhaustive by default outside the module in Swift 5
exhaustive keyword to change the default behaviour

Like that, we don’t need nonexhaustive.

Thoughts?
David.

On 13 Sep 2017, at 21:16, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Haha no problems. Yes, it seems clear people are jumping to conclusions. This is a case specifically for framework developers purely for interface consistency, with is *exactly* when you want the default behaviour to protect you from external dependency changes.

Within the context of a single application at compile time, you will always know all cases already and therefore exhaustive can become the default. Cross frameworks, not so much.

···

On 18 Sep 2017, at 9:46 am, Christopher Kornher <ckornher@me.com> wrote:

On Sep 17, 2017, at 5:04 PM, BJ Homer <bjhomer@gmail.com <mailto:bjhomer@gmail.com>> wrote:

Please note that, as proposed, enums are always treated as exhaustive *within the same module*. A new user writing MyFirstEnum is likely using it within the same module, and will thus get exhaustive behavior with no extra keywords required.

• What is your evaluation of the proposal?
  Uh, +1

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

Apologies for wasting everyone’s time…

“… what you're describing isn't really an enum"

I’ve gotten this explanation before in reference to errors. I am confused as to what constitutes an enum and what doesn’t.

-Kenny

···

On Sep 18, 2017, at 10:31 AM, Jordan Rose <jordan_rose@apple.com> wrote:

As mentioned, the right way to do this is with a struct:

public struct ConnectionDictionaryKey: RawRepresentable, Hashable {
  public var rawValue: String
  public init(rawValue: String) { … }
  public init(_ rawValue: String) { … }
}
extension ConnectionDictionaryKey {
  static let hostName = ConnectionDictionaryKey("hostname")
  static let databaseName = ConnectionDictionaryKey("database")
  // …
}

It is definitely more verbose than an enum, and it may be worth a separate proposal to deal with that! But it is not part of this proposal, and what you're describing isn't really an enum.

Jordan

On Sep 16, 2017, at 15:51, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Oops, forgot something:

"Can there be a kind of open enum where you can add new cases in extensions?”

I have a use case for this. I’m trying to write a database ORM with abstract API and concrete instances for different database. So I have defined:

open class Database {
   init(connectionDictionary: [ConnectionDictionaryKey:String]) {
        self.connectionDictionary = connectionDictionary;
    }
}

Where I have ConnectionDictionaryKey defined as an enum, with values like .hostName, .databaseName, .userName, .password, .databaseName, etc…

But concrete databases may have other options that need to be added to the connection dictionary. It would be nice if they could just extend ConnectionDictionaryKey with new cases.

-Kenny

On Sep 16, 2017, at 3:35 PM, Kenny Leung via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

In general, I agree with everything in the proposal.

I’d like to propose these alternative extensions for clients:

1) As a client of an enum, I’d like to know in the future when a new value has been added to an enum, since I may have to do something about it. How about adding the “exhaustive” keyword to be used in the switch statement? Like

exhaustive switch excuse {
    case eatenByPet:
        // …
    case thoughtItWasDueNextWeek:
        // …
    default:
        // …
}

If exhaustive is used, there would be a warning if all cases aren’t covered *even though default exists*. This means that I as the client thought I had everything covered when I wrote this code.

As already mentioned, this makes the default case un-testable, which brings me to

2) All non-exhaustive enums should have the pseudo value “default” that can be used just like a regular value. This would allow you to write code like:

teacher.failedToHandInHomework(excuse: .default)

which would allow you to trip the default case in any code you may write.

-Kenny

On Sep 13, 2017, at 12:17 PM, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Proposal updated, same URL: https://github.com/jrose-apple/swift-evolution/blob/non-exhaustive-enums/proposals/nnnn-non-exhaustive-enums.md\.

Thanks again for all the feedback so far, everyone!
Jordan

On Sep 12, 2017, at 17:55, Jordan Rose via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

Sorry, I got distracted by other tasks! Both the discussion here and within Apple has moved towards making "non-exhaustive" the default, which, to be honest, I too think is the best design. I'll update the proposal today to reflect that, though I still want to keep both the "nonexhaustive" and "exhaustive" keywords for Swift 4 compatibility for now (or whatever we end up naming them). The compatibility design is a little less ambitious than Brent's; as currently proposed, Swift 4 mode continues to default to 'exhaustive' all the time, even in the actual Swift 5 release.

I still want to respond to Brent's points directly, but I think you and Vladimir have done a good job discussing them already. I'll send out the updated proposal tomorrow, after I have a little more time to think about #invalid.

Thanks for putting time into this!
Jordan

On Sep 9, 2017, at 17:34, Rod Brown <rodney.brown6@icloud.com <mailto:rodney.brown6@icloud.com>> wrote:

Jordan,

Do you have any other thoughts about the ongoing discussion here, especially regarding Chris’ comments? As you’re the one pushing this forward, I’d really like to know what your thoughts are regarding this?

- Rod

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my iPad

I run into use cases like this all the time…

I think I would prefer to see those concrete cases in a subtype though:

  enum DrinkSize {
    case small
    case medium
    case large
  }

  enum SummerDrinkSize : DrinkSize {
    //Inherits DrinkSize’s cases
    case extraLarge
  }

Because it is a subtype, you could place a SummerDrinkSize anywhere you can put a DrinkSize. As a result, all switches on it would need a default case to handle cases they hadn’t planned for. If you mark an enum with “final” then it can’t be extended and switches can be exhaustive.

You have the subtype relationship backwards here. DrinkSize is a subtype of SummerDrinkSize. All values of DrinkSize are also valid values of SummerDrinkSize but not vice versa. For this reason, inheritance syntax doesn't make sense. The syntax that makes more sense is some kind of case embedding syntax:

enum SummerDrinkSize {
    cases DrinkSize
    case extraLarge
}

I disagree. I get that the shape of a DrinkSize would always fit in a SummerDrinkSize hole (ignoring the overriding/extension of methods), but the fact that we are requiring ‘default’ in switches changes the calculus. Basically, it changed when we decided to change whether exhaustive was the default. The point is to make people consider that they may have cases which they may not expect. That is much easier with a concrete idea of subtype, which people are already used to.

In addition to inheriting the cases, a subtype would also inherit, and be able to override, methods defined on the super-type. You could use super to call the super-type’s implementation.

I think implementation sharing is a bad idea for value types. Value subtyping should be conceptualized as a restricted mechanism for value-preserving implicit conversion.

Why?

···

On Sep 17, 2017, at 7:55 AM, Matthew Johnson <matthew@anandabits.com> wrote:
On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution <swift-evolution@swift.org <mailto:swift-evolution@swift.org>> wrote:

I just noticed this too. I guess I was looking too closely at the “Default behavior” section.The inlining caveat scares me a little, as it would seem to have rather drastic consequences in the future, essentially requiring the worst case scenario, even in the same module, if we want inlining for functions that use enums.

Jon

···

On Sep 17, 2017, at 9:09 PM, Rod Brown via swift-evolution <swift-evolution@swift.org> wrote:

On 18 Sep 2017, at 9:46 am, Christopher Kornher <ckornher@me.com <mailto:ckornher@me.com>> wrote:

On Sep 17, 2017, at 5:04 PM, BJ Homer <bjhomer@gmail.com <mailto:bjhomer@gmail.com>> wrote:

Please note that, as proposed, enums are always treated as exhaustive *within the same module*. A new user writing MyFirstEnum is likely using it within the same module, and will thus get exhaustive behavior with no extra keywords required.

• What is your evaluation of the proposal?
  Uh, +1

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

Apologies for wasting everyone’s time…

Haha no problems. Yes, it seems clear people are jumping to conclusions. This is a case specifically for framework developers purely for interface consistency, with is *exactly* when you want the default behaviour to protect you from external dependency changes.

Within the context of a single application at compile time, you will always know all cases already and therefore exhaustive can become the default. Cross frameworks, not so much.

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org <mailto:swift-evolution@swift.org>
https://lists.swift.org/mailman/listinfo/swift-evolution

Sent from my iPad

I run into use cases like this all the time…

I think I would prefer to see those concrete cases in a subtype though:

  enum DrinkSize {
    case small
    case medium
    case large
  }

  enum SummerDrinkSize : DrinkSize {
    //Inherits DrinkSize’s cases
    case extraLarge
  }

Because it is a subtype, you could place a SummerDrinkSize anywhere you can put a DrinkSize. As a result, all switches on it would need a default case to handle cases they hadn’t planned for. If you mark an enum with “final” then it can’t be extended and switches can be exhaustive.

You have the subtype relationship backwards here. DrinkSize is a subtype of SummerDrinkSize. All values of DrinkSize are also valid values of SummerDrinkSize but not vice versa. For this reason, inheritance syntax doesn't make sense. The syntax that makes more sense is some kind of case embedding syntax:

enum SummerDrinkSize {
    cases DrinkSize
    case extraLarge
}

I disagree. I get that the shape of a DrinkSize would always fit in a SummerDrinkSize hole (ignoring the overriding/extension of methods), but the fact that we are requiring ‘default’ in switches changes the calculus. Basically, it changed when we decided to change whether exhaustive was the default. The point is to make people consider that they may have cases which they may not expect. That is much easier with a concrete idea of subtype, which people are already used to.

Requiring developers to consider cases that may be added to an enum in the future is orthogonal to any potential subtype relationship between two value types.

In addition to inheriting the cases, a subtype would also inherit, and be able to override, methods defined on the super-type. You could use super to call the super-type’s implementation.

I think implementation sharing is a bad idea for value types. Value subtyping should be conceptualized as a restricted mechanism for value-preserving implicit conversion.

Why?

First, this is how value subtyping already works in the case of Optional where `T` is a subtype of `T?`.

More generally, this approach is roughly analogous to implicit promotion in C-family languages. We want `Int8` to be a subtype of `Int16`, `Int32`, `Int`, etc.

This approach allows a value type to have multiple value-preserving supertypes without the performance impact of dynamic dispatch or the complexity of multiple inheritance.

···

Sent from my iPad

On Sep 17, 2017, at 5:02 PM, Jonathan Hull <jhull@gbis.com> wrote:

On Sep 17, 2017, at 7:55 AM, Matthew Johnson <matthew@anandabits.com> wrote:

On Sep 17, 2017, at 3:37 AM, Jonathan Hull via swift-evolution <swift-evolution@swift.org> wrote: