Why force unwrapping is required in case of enum and switch?

i0S Swift Issue

Question or problem with Swift language programming:

I have notice weird swift behaviour, because in my opinion colours variable shouldn’t be force unwrapped in case of switch written below, but without unwrapping compiler shows me an error message.

enum Colours: Int {
case Red = 0, White, Black
}

var colours: Colours!
colours = .Red

switch colours! { // <-- why I have to unwrap colours? As you can see colours are declared as '!'
case .Red: break
default: break
}

if colours variable is not unwrapped compiler shows me that error:

in my opinion it is swift inconsistency, does anyone have some ideas?

How to solve the problem:

Solution 1:

Update: This has been fixed in Swift 5.1. From the CHANGELOG:


SR-7799:
Enum cases can now be matched against an optional enum without requiring a '?' at the end of the pattern.

This applies to your case of implicitly unwrapped optionals as well:

var colours: Colours!

switch colours {
case .red:
    break    // colours is .red
default:
    break    // colours is .white, .black or nil
}

Previous answer:

When used in a switch statement, even implicitly unwrapped
optionals are not automatically unwrapped. (A reason might be that you
could not match them against nil otherwise.)

So you have to unwrap (either forcibly with
colours! which will crash if colours == nil, or with optional binding), or – alternatively – match against .Red?
which is a shortcut for .Some(.Red):

var colours: Colours!

switch colours {
case .Red?:
    break    // colours is .Red
default:
    break    // colours is .White, .Black or nil
}

The same holds for other pattern-matching expressions, e.g.

if case .Red? = colours {
    // colours is .Red 
} else {
    // colours is .White, .Black or nil
}

Also this has nothing to do with enumeration types, only with implicitly
unwrapped optionals in a pattern:

let x : Int! = 1

switch x {
case nil:
    break // x is nil
case 1?:
    break // x is 1
default:
    break // x is some other number
}

Solution 2:

This is because you create colours variable like optional type. If you do like this:

var colours: Colours
colours = .Red

you will not have to unwrappe this value

If we look at what the optional type is, we will see that this is enum like:

enum Optional {
    case Some(T)
    case None
}

And it can be Some Type like Int for example or None and in this case it's have nil value.

When you make this:

var colours: Colours!

you directly is indicated by the ! that this is not Colours type but this is the enum ImplicitlyUnwrappedOptional<Colours> type. At moment of creation it's will be Some<Colours> if equal it value but with this ! you have that it is enum ImplicitlyUnwrappedOptional<Colours> and in some next moment it will be the None. That's why you have to use ! in switch:

Your colours value is ImplicitlyUnwrappedOptional<Colours> type and it may be Colours or nil and you have to directly indicate that this is Colours type in `switch``.

Solution 3:

Instead of using :

var colours: Colours!
colours = .Red

Simply use

var colours = Colours.Red

That should do the trick.

Hope this helps!