#### Let
This is where it gets ugly. Let has no opinions about null, but
the game here is to pretend it does. So in a let statement:
let P = e
- Evaluate e
- If e is null
- If P is a covering pattern, its binding is bound to null;
- else we throws NPE
- Otherwise, e is matched to P. If it does not match (its
remainder), a MatchException is thrown (or the else clause is
taken, if one is present.)
It's not clear to me why a MatchException should be thrown instead of
not compiling if not exhaustive.
You're confusing "exhaustive" and "total". A let must be exhaustive,
but exhaustiveness != totality.
It's mean that there are remainders that does not lead to either a NPE
or an error, do you have an example of such remainder ?
Yes. Suppose we have records Box<T>(T t) and Pair<T, U>(T t, U u), and
A is sealed to B|C. Then if we're matching on a Pair<Box<A>, A>, then
Pair(null, B)
Pair(Box(B), D) // D is a type from the future
Pair(Box(D), B)
Pair(Box(D), D)
Pair(null, D)
are all in the remainder. It is a big stretch to claim either NPE or
ICCE is right for any of these, and completely arbitrary to pick one for
Pair(null, D). Also, its much more expensive to try to distinguish
between these, and pick the "right" error for each, rather than insert a
default clause that throws MatchRemainderException.