Skip to content

match & exhaustiveness

A closed enum is only half the deal. The other half is match — the tool that takes a Value apart — and its defining property: the compiler will not let you forget a case. That guarantee is not a nicety; it’s load-bearing for a system with nine value shapes dispatched on in dozens of places.

You’ll be able to: read a match over Value, and explain why exhaustiveness turns “add a tenth shape” from a hunt-for-every-site nightmare into a compiler-guided chore.

The engine constantly needs to ask a Value “what shape are you?” — for diagnostics, for coercion, for error messages. Value::type_name answers it with one match over all nine variants:

clinker-record ·value.rs ·type_name fn @47d2e12
pub fn type_name(&self) -> &'static str {
match self {
Value::Null => "null",
Value::Bool(_) => "bool",
Value::Integer(_) => "integer",
Value::Float(_) => "float",
Value::String(_) => "string",
// ... one arm per variant, all nine
}
}

Each arm names a variant; (_) says “I don’t care about the payload, just the shape.”

A match must cover every variant — leave one out and the code won’t compile. That sounds like nagging until you imagine the alternative. Value is dispatched on across the whole engine: coercion, comparison, serialization, formatting. Now suppose a tenth shape is added. With exhaustive match, the compiler immediately lists every single site that must be updated — miss none, ship nothing half-handled. Without it, you’d be grepping and praying.

This is the deep reason the closed enum from the last lesson pays off: closed set + exhaustive match = the compiler is a complete, always-current checklist of “have you handled every case?” (It’s also why reaching for a _ => catch-all is a smell in this codebase — it silences exactly the warning you want.)

rust // editable

It compiles and prints three type names. Now delete the Value::Float arm and Run. The compiler stops you with an error — non-exhaustive patterns: &Value::Float(_) not covered — naming the exact case you dropped.

// quick check

Why is `match` being exhaustive a benefit when adding a new Value variant?

You can take a Value apart safely. Next: how the engine passes records around without copying them — the ownership rules that make it fast.