46

The Apple documentation says

Every switch statement must be exhaustive. That is, every possible value of the type being considered must be matched by one of the switch cases.

So in new Xcode I have placed a code like this

println(UInt16.min); // Output : '0' println(UInt16.max); // Output : '65535' var quantity : UInt16 = 10; switch quantity { case 0...65535: //OR case UInt16.min...UInt16.max: println(); default: println(); } 

Now if i remove the default section I get a compiler error:

Switch must be exhaustive
Do you want to add missing cases? Fix

So my question is for a case that I have mentioned as case 0...65535: have I not mentioned all the case values for an UInt16 ?? But still I am getting an error ?? Why am I getting this error, Did i miss something ??

2
  • 1
    This code compiles with Xcode 7.3/Swift 2.2, so the compiler has become smarter :) Commented Apr 7, 2016 at 13:09
  • 2
    ... but it crashes at runtime :( Commented Apr 7, 2016 at 13:20

5 Answers 5

99

Swift only truly verifies that a switch block is exhaustive when working with enum types. Even a switching on Bool requires a default block in addition to true and false:

var b = true switch b { case true: println("true") case false: println("false") } // error: switch must be exhaustive, consider adding a default clause 

With an enum, however, the compiler is happy to only look at the two cases:

enum MyBool { case True case False } var b = MyBool.True switch b { case .True: println("true") case .False: println("false") } 

If you need to include a default block for the compiler's sake but don't have anything for it to do, the break keyword comes in handy:

var b = true switch b { case true: println("true") case false: println("false") default: break } 
Sign up to request clarification or add additional context in comments.

6 Comments

So you mean iOS says its exhaustive but it actually is not ?
I just experienced this with a non-optional Bool and thought I was missing something. I filed a bug report: 19582311
switch no longer requires default for Bool if you have cases for true and false. I'm not sure when this change happened, but with Swift 2.2 in Xcode 7.3, the above works.
@NateCook . Just checked on xCode 10, default is not required for Bool if true and false are present. "error: switch must be exhaustive" is not coming
Confirmed; this answer is no longer true in Swift. I would suspect since Swift 2 or 3.
|
11

Part of why you see that error because the compiler can't verify that switch is exhaustive without running code. The expression 0...65535 creates a ClosedInterval struct, and when the switch statement executes it has to ask that struct if the value quantity is in the interval. There's room for that to change at run time, so the compiler can't check it at compile time. (See the Halting Problem.)

More generally, the compiler can't detect an exhaustive switch for integer values — even if you add specific cases for every integer value (case 0: ... case 1: ... ... case 65535:), it doesn't know your switch is exhaustive. (Theoretically it could, though: consider filing a feature request about this if it's something you'd like to see.)

As it stands, there are two scenarios where Swift can detect completeness and allow you to omit the default clause: enums and value binding in tuples. @NateCook's answer covers enums — if you switch on an enum value and have a case in your switch for every case in the enum, you don't need a default. You also don't need a default label if you switch on a tuple and bind every possible combination of values, as seen in the Swift book:

switch anotherPoint { case (let x, 0): println("on the x-axis with an x value of \(x)") case (0, let y): println("on the y-axis with a y value of \(y)") case let (x, y): println("somewhere else at (\(x), \(y))") } 

You might generalize this rule as "if the type system knows about the possible values of your type, it can detect switch completeness", but the fact that there's a level on which the type system doesn't know the range of possible (e.g.) UInt32 values is sort of splitting hairs...

4 Comments

Nope...tried it with UInt8 and it prompts you to add a default case even with all 256 numbers.
Ehh, that's what I get for posting from my phone and going off what I half remember. :) Edited answer with corrections and some further info.
"the compiler can't verify that switch is exhaustive without running code" - that is simply not true.
A third case now works without default. A switch on a Bool doesn't require a default case if both true and false are covered.
2

Swift 4.1. Either you need to specify all cases or Just include default block inside switch statement.

Comments

2

(As of Swift 4.2, and probably earlier): I have a helper function that converts a Bool? into the selectedSegmentIndex for a UISegmentedControl with 2 segments. If the value is nil then neither segment should be selected. My function uses a switch, which returns the appropriate segment index for true or false values, and uses this to explicitly test for the nil and satisfy the compiler's need for it to be exhaustive:

case nil: // only remaining possible value fallthrough default: return UISegmentedControl.noSegment 

Technically, the case nil: fallthrough isn't required because the default: will suffice, but this syntax may be useful if you want to explicitly test a value to make the code more self-documenting, or perhaps in another situation.

Comments

1

Check if your enum was initialised as an optional which could be either case or nil

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.