[pattern-switch] Is totality too subtle?

Brian Goetz brian.goetz at oracle.com
Fri Aug 14 17:20:33 UTC 2020


I just want to summarize what's been said on this:

>  - Is totality too subtle? (Remi) There is some concern that the 
> notion of using totality to subsume nullability (at least in nested 
> contexts) is sound, he is concerned that the difference between total 
> and non-total patterns may be too subtle, and this may lead to NPE 
> issues.  To evaluate this, we need to evaluate both the "is totality 
> too subtle" and the "how much are we worried about NPE in this 
> context" directions.

... but I'd like to do so without repeating what has been said before.  
So please, new observations only.

A key assumption underlying the proposed semantics of nullity in 
patterns (not switches) stems from the notion that definition of 
matching a pattern should be independent of the semantics of its 
consuming construct.  Instanceof and switch may have pre-existing 
opinions about patterns, but we should be wary about polluting those.  A 
pattern should mean something on its own.

Totality is defined relative to a target type; `String s` may be total 
on String, but definitely not on Object.  We can view a nested pattern 
as a tree; as Guy observed, totality is a property of a _sub-tree_ of 
this tree, which might be one leaf, the whole tree, or some sub-tree of 
the tree.  But a node cannot be total on its target if the sub-trees are 
not total on their corresponding target.

Further, the above property is desirable; we anticipate that catch-alls 
for an entire pattern chain, or for a sub-chain of a pattern chain, will 
be common, because they are useful; being able to say "Box containing 
anything", and destructure it at the same time, is an essential case 
that pattern matching should cover.  This requires the existence of leaf 
(type) patterns that are nullable.  One way to get there is with the 
current proposal; another is to have two of every kind of pattern (or a 
modifier on patterns) to add in or subtract out nullity.

The main concern, if I understand it correctly, comes in the context of 
switch.  The switch header is already "at a distance" from the 
possibly-total (at the bottom); the type of the switch target may be 
further "at a distance" (because of var, expression nesting, etc), and 
so the concern is it may not be sufficiently obvious that a pattern is 
total, and therefore the semantics of the switch may not be sufficiently 
obvious.

To the extent there are two ways to write a pattern (or compose two 
patterns), identical except for nullability, the choice of which is the 
default (nullable or not) is extremely consequential for actual user 
experience.

I think the above is largely neutral and agreed on.  Now, some personal 
observations:

  - I think the concern that "it will be too hard to tell if a switch is 
meant to be exhaustive" is overblown.  Catch-all switches typically look 
like catch-alls, both because of what they say and where they are 
placed.  There will be common patterns of cases, which may not be 
familiar to everyone now, but will be very familiar soon enough, which 
will provide significant context for helping to understand the author 
intent.

  - Even if the above concern is not overblown, I think the consequences 
of getting it wrong may still be.  Yes, the null-handling behaviors of 
some switches may not be obvious, but: (a) right now, no switch ever 
deals with null at all, and there is not an epidemic of NPEs flying out 
of switches, and (b) what this does is move the null handling from a 
place where it always throws to a place where it might throw if the user 
is not careful.  Multiplying the low probability of nulls showing up at 
the gate unexpected in the first place, by the low conditional 
probability that this will make things worse, it seems like we're pretty 
deep in corner-case-of-a-corner-case.

  - I think that many of the proposed "remedies" are misguided.  Many of 
the action-at-a-distance concerns can be likened to the interaction 
between `var` and diamond; yes, when you combine two features that have 
some degree of implicitness, things get less obvious.  But the answer is 
not "don't do var", or "disallow var in the presence of diamond" 
(because they do interact in a well-behaved and potentially useful way), 
it is to warn users to not go overboard on being implicit everywhere 
they possibly can; use `var` where it adds value, and don't use it where 
it doesn't.

So, while I am sympathetic to the concerns, I am skeptical that this is 
such a big problem that we have to distort the language (and force users 
to reason about nullity on every pattern.)  All the cures proposed so 
far seem much worse than the disease.

We still need to work through the other nullity issues, which might 
cause some rearrangement of the deck chairs.  So at the very least, 
let's let this one lie for a while, until the others are worked out, but 
assuming that causes no change, I am of the opinion that we should do 
nothing now, and revisit in Preview/2 in light of actual experience, to 
see if it turns out that people can't handle the current behavior.  I 
think we're in deep danger of extrapolating from an abstract fear.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.java.net/pipermail/amber-spec-experts/attachments/20200814/3685b033/attachment-0001.htm>


More information about the amber-spec-experts mailing list