Why can switch on an Optional use .none / .some and also nil?

1.2.2 · L5 · Learning

Predict first

Does this compile?

func label(_ x: Int?) -> String {
    switch x {
    case .some(let v): return "\(v)"
    case nil: return "none"
    }
}
  • Yes
  • No — mixes nil and .some

Mental model. Two spellings, one enum. nil is a literal for .none, the way 0 is a literal for an Int.

Because Optional is an enum and pattern matching is structural. case .none and case nil are the same pattern; case .some(let x) and case let x? are the same pattern.

This is why optional “magic” is not magic: if let, ??, and optional chaining are all sugar over enum matching and a standard-library flatMap.

nil is a literal for .none, so both patterns cover the same two cases and the switch is exhaustive.

Common traps

  • Thinking nil is a keyword in the language. It is a literal expression, and it only makes sense in an optional context.
  • Assuming the representation is fixed. For class references the compiler usually uses the null pointer; for structs it may use a spare bit pattern or extra storage. Do not depend on it.

They might follow up with

  • What does Optional.some(Optional.none) look like? A non-nil optional wrapping a nil optional — Int?? with an outer .some. This is the double-optional bug from Q15.
  • Can you add methods to Optional? Yes, via an extension with where Wrapped == ... constraints.

Related questions

  • 1.2.1 What is an Optional in Swift, and what is it internally?
  • 1.2.5 What is the difference between if case, guard case, and switch on an enum?
  • 1.2.7 What is flatMap vs map on Optional? What about Optional.map vs array map?

← What is an Optional in Swift, and what is it internally?   if let vs guard let vs ?? vs force unwrap — when is each one OK? →