- i don't think that framing the problem we have in term of null
haters / null friends is productive.
It may not be productive, but it is one of the elephants in the room.
Some people sometimes take a hostile view of null ("We should prevent
stream elements from being null!"), and, while this is often motivated
by the best of intentions, it is a bias we need to be aware of.
- match :: (Pattern t) u -> Maybe t, the railway design pattern as
coined by Scott Wlaschin[1], means that __each__ matcher is able to
decide what to do with null, so it's a more lax model as the one we
are working on.
Seems like exactly the model we are working on. Some patterns can match
null (total type patterns, any patterns, null constant pattern) and some
cannot (deconstruction patterns, non-null constant patterns.)
Eventually, there will be a way to write patterns in Java code (e.g.,
deconstruction patterns for arbitrary classes), but we can still make
the "null OK / null not OK" decision for these entire categories at
once, so humans and compilers can reason about them.
There is a way to see a switch as a cascade of instanceof and to allow
null,
Herein lies danger, as both `switch` and `instanceof` have pre-existing,
somewhat accidental null opinions. But I agree that it is a good goal
that switches and if-else chains of instanceof tests on the same target
be refactorable to each other to the extent possible.
This is almost the same semantics as the one you are proposing but
instead of the notion of totality, being the last case is enough to
accept null.
... but what if the switch isn't total? I can have
switch (o) {
case Integer i: ...
case String s: ...
// no default, no total pattern
}
and it would be quite surprising to randomly shove nulls into the last
case. This would prevent the cases from being reordered even though
they have no dominance ordering. The reason the last case is special in
the examples we've given so far is ... wait for it ... THEY ARE TOTAL.
It would be a compiler error to have any more cases after them. They
are intrinsically catch-alls.
I prefer this semantics, because it's local, the last case allows
null, it doesn't depends on the type of v or the relationship between
A and B.
This proposal seems entirely motivated by "let's have a really simple
rule", rather than based on principles of what actually should happen in
real programs or what programs should be expressible. And, regardless
of motivation, it is surely the wrong answer.