swiftPunk
swiftPunk

Reputation: 1

Why switch does not accept case nil in optional?

I was working with optional in switch which I noticed switch cannot accept nil as a case!

func test(value: Bool?) {
    switch value {
    case true: print("true")
    case false: print("false")
    case nil: print("nil")
    }
}

Error: Switch must be exhaustive

then I used default for solving the issue, but I am looking to learn why nil cannot work in first code?

Upvotes: 2

Views: 516

Answers (2)

valeCocoa
valeCocoa

Reputation: 344

An Optional is an enum with two cases, one which has the value associated: either .some(value) or .none

The correct way to use a switch for pattern matching an optional is:

switch optional {
case .some(let value): // do your stuff with value
case .none: // do your stuff when the optional is nil
}

Alternatively you could also use map on an optional to execute a closure when its value is not nil:

optional.map { value in 
    // do your stuff with the value 
}

With this approach the body closure passed to the map function only executes when the optional is not nil at runtime, otherwise it doesn’t executes.

Upvotes: 0

Alexander
Alexander

Reputation: 63167

I think this is just an incorrect diagnostic. You can add a default case, and this code will work, but I'm actually surprised that works.

You see, the value you're switching on is a Bool?, but 2 of the values you're comparing it against are true and false. The typical approach for this is to use pattern matching:

func test(value: Bool?) {
    switch value {
    case .some(true): print("true")
    case .some(false): print("false")
    case .none: print("nil")
    }
}

This works correctly, but it's a bit wordy. Luckily, Swift has a syntactic sugar for pattern matching against optionals, ? and nil:

func test(value: Bool?) {
    switch value {
    case true?: print("true")
    case false?: print("false")
    case nil: print("nil")
    }
}

Both of these snippets compile and work fine. It does open a new question as to why your original cases worked, if only you added the default.

I suggest you post about this on Swift forums, to get more input from the compiler nerds :)

Upvotes: 6

Related Questions