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 ??
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
}
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...
Swift 4.1. Either you need to specify all cases or Just include default block inside switch statement.
(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.
Check if your enum was initialised as an optional which could be either case or nil
Related
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 ??
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
}
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...
Swift 4.1. Either you need to specify all cases or Just include default block inside switch statement.
(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.
Check if your enum was initialised as an optional which could be either case or nil
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 ??
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
}
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...
Swift 4.1. Either you need to specify all cases or Just include default block inside switch statement.
(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.
Check if your enum was initialised as an optional which could be either case or nil
Is it possible in Swift to pattern match and extract the initial value (now cast) at the same time?
For example, if I had these enums:
enum Inner {
case a(Int)
case b(Int)
}
enum Outer {
case one
case two(Inner)
}
and I wanted to match Outer.two(Inner.a(1)) and have have a variable cast to that at the same time
let value: Any // Could be anything :|
switch value {
case let a as Outer.two(Inner.a(1)):
// Do something which needs `a`
default"
// Do some other things
}
Obviously, that doesn't work because as only casts to types.
I've also tried
case Outer.two(let a) where a == Inner.a(1):
case let Outer.two(.a(1)) = a: // i.e. the syntax in "guard case let ..."
which don't work. (NB The first would work, but implementing == isn't an option for me, annoyingly)
FYI: Scala lets you do it with the # operator, something like this:
case a # Outer.two(Inner.a(1)):
Is there a syntax which can do this, or do I need to rethink how I'm solving my problem?
I don't think there is an equivalent pattern to
case a # Outer.two(Inner.a(1)): in Swift. Here is a possible
workaround:
switch value {
case Outer.two(Inner.a(1)):
let a = Inner.a(1)
// Do something which needs `a`
default:
// Do some other things
}
I have a 2D array : var matrixOfMutableObjects: Array<Array<Any>>
But when i try to check if the value on a certain position of the Array is a enum that i created the compiler complains: Cannot subscript a value of type 'inout Array<Array<Any>>
if(x < 0 || x > ROWS || y < 0 || y > COLS){
return false;
} else if (matrixOfMutableObjects[x][y] != enumObject.NOTHING){
return false;
}
Why cant i verify if the element in the position x,y of my Array is of the type enumObject.NOTHING that i created??
public enum enumObject {
case NOTHING
case Wall
}
Pattern matching (used for matching cases in enum instances) and equality testing are two different things.
Also, an object wrapped in Any is only known to the compiler as Any, so you need to perform an attempted conversion to a given type prior to applying e.g. pattern matching vs cases of that type (say, if the type converted to is an enum).
E.g.:
public enum enumObject {
case NOTHING
case Wall
}
var matrixOfMutableObjects: Array<Array<Any>> = [
[1, "two"],
[enumObject.NOTHING, 4.2]
]
let x = 1
let y = 0
// no bounds checking in this simple example!
if case .some(.NOTHING) = matrixOfMutableObjects[x][y] as? enumObject {
print("Is nothing!")
}
Or, using the ? syntactic sugar:
// ...
if case .NOTHING? = matrixOfMutableObjects[x][y] as? enumObject {
print("Is nothing!")
}
Note that the outer .some(...) pattern matching (or ? sugar) checks that the attempted conversion of the element to enumObject is successful. If that is the case, an additional pattern matching of is performed for the wrapped object (which is then known to be of type enumObject) to a given case of enumObject (.NOTHING, specifically).
Curiosities of Swift: avoiding the explicit type conversion
As pointed out by #Hamish in a comment below, it seems that enum case pattern matching can actually perform the conditional type casting for you, meaning you needn't resort to the explicit casting and nested pattern matching above (as? and .some(...)/?, respectively), but can simply use pattern matching against the NOTHING case directly, given that you also supply the enum type:
if case enumObject.NOTHING = matrixOfMutableObjects[x][y] {
print("Is nothing!")
}
Finally, note that the Swift API Guidelines prescribes lowercase enum cases, so you might want to use the cases nothing and wall, rather than NOTHING and Wall, and additionally CamelCase name convention for types (so prefer EnumObject over enumObject).
I know it is possible to test an optional vs optionals as described in this question: Swift: testing against optional value in switch case
But what I want to do is test a non-optional value with optional case values:
switch nonOptionalView{
case optionalView1:
// Do something
case optionalView2:
// Do something else
}
Xcode returns an error "Value of Optional xxx not unwrapped"
and If I add a "?" at the end of the case statement, I get "? pattern cannot match values of type 'UIView'"
Currently pattern matching optional values isn't supported in the Swift standard library. However, you could easily execute your logic using if/else if statements:
if nonOptionalView === optionalView1 {
// Do something
} else if nonOptionalView === optionalView2 {
// Do something else
}
If you'd really like to be able to pattern match optional values, you can use operator overloading. To overload the pattern matching operator ~=, place the following code in your project:
public func ~=<T : Equatable>(a: T?, b: T?) -> Bool {
return a == b
}
Now you'll be able to pattern match optional values just fine:
switch nonOptionalView {
case optionalView1:
// Do something
case optionalView2:
// Do something else
default:
// Handle default case
}
You could take a look at this solution https://stackoverflow.com/a/26941591/2485238
I find the code is more readable than the if/else solution.
In your case it would be
switch nonOptionalView {
case .Some(optionalView1):
// Do something
case .Some(optionalView2):
// Do something else
default:
// Handle default case
}