Why can switch on an Optional use .none / .some and also nil?
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
nilis 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 withwhere 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? →