[swift-evolution] Enums and Source Compatibility

Vladimir.S svabox at gmail.com
Tue Sep 19 06:39:41 CDT 2017

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.

* 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.

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 at swift.org <mailto:swift-evolution at 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 at swift.org
> https://lists.swift.org/mailman/listinfo/swift-evolution

More information about the swift-evolution mailing list