Nullable switch
Brian Goetz
brian.goetz at oracle.com
Thu Aug 6 22:14:03 UTC 2020
If we were paying the full cost of nullable types (T?), then there would
be an obvious choice: T would be a non-nullable type pattern, and T?
would be a nullable type pattern. But introducing an `any Foo` notion
has similar conceptual surface area, but dramatically less utility. So
the "return on syntax" for "any Foo" is not good.
We were considering T? at one point, back when we were considering T?
over in Valhalla land, but as soon as that didn't pan out over there,
the attractiveness of using it over here pretty quickly went to zero.
The argument for using totality to wriggle out of the nullity trap is a
sophisticated one, which may be part of the problem, but it is largely
about uniformity (and partially a pick-your-poison.)
I think this is a forced move: that
case Box(var o):
be total (including Box(null)). Any other conclusion is hard to take
seriously. If this excludes Box(null), users will make frequent errors
-- because users routinely ignore null's special behaviors (and we
mostly want them to keep doing so.)
The next step is a principled one: It's not acceptable for `var`
patterns to be inconsistent with type inference. The choice Scala/C#
made here is terrible, that switching between an inferred and manifest
type changes the semantics of the match. Super Not OK. So that means
case Box(Object o):
has to be total on boxes too.
Another principled choice is that we want the invariant that
x <matches> P(Q)
and
x <matches> P(var alpha) && alpha <matches> Q
be equivalent. The alternative will lead to bad refactoring anomalies
and bugs. (You can consider things like this as being analogous to the
monad laws; they're what let you freely refactor forms that users will
assume are equivalent.)
Which leads us right to: the pattern `Object o` is total on Object --
including null. (If `instanceof` or `switch` have a rigid opinion on
nullity, we won't get to the part where we try the match, but it can
still be a nullable pattern.)
You can make a similar argument for refactoring between if-else chains
and switches, or between switch-of-nest and nested switch:
switch (b) {
case Box(Frog f): ... <-- partial
case Box(Object o): ... <-- total
}
should be equivalent to
switch (b) {
case Box(var x):
switch (x) {
case Frog f:
case Object o: <-- must match null, otherwise
refactoring is invalid
}
}
But if the inner switch throws NPE, our refactoring is broken. Sharp
edge, user is bleeding.
You're saying that the language is better without asking users to reason
about complex rules about nullity. But the cost of this is sharp edges
when refactoring (swap var for manifest type, swap instanceof chain for
switch, swap nested pattern switch for switch of nested pattern), and
user surprises. The complexity isn't gone, its just moved to where we
we don't talk about it, but it is still waiting there to cut your fingers.
The totality rule is grounded in principle, and leads to the "obvious"
answers in the most important cases. Yes, it's a little more
complicated. But the alternative just distributes the complication
around the room, like the shards of a broken window no one has bothered
to clean up.
On 8/6/2020 5:35 PM, forax at univ-mlv.fr wrote:
> I've re-read the proposed spec about the nullable switch,
> and it still don't understand why people will think that that the
> following switch is a nullable switch
> switch(o) {
> case String s ->
> case Object o ->
> }
It's not clear that they have to. Right now, switches throw hard on
null, and yet the world is not full of NPEs that come from switches. So
most users don't even consider null when writing switches, and somehow
it all works out. The last thing we want to do is grab them by the
collar, shake them, and say "you are a bad programmer, not thinking
about nulls in switch! You must start obsessing over it immediately!"
Instead, if they're in blissful ignorance now, let's let them stay
there. Let's make the idioms do the obvious thing (Box(var x) matches
all boxes), and then, for the 1% of users who find they need to reason
about nulls, give them rules they can understand.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200806/b738370f/attachment.htm>
More information about the amber-spec-experts
mailing list