[pattern-switch] Summary of open issues
Brian Goetz
brian.goetz at oracle.com
Sun Aug 23 16:23:56 UTC 2020
It's a good time to check in on this list, because I think we've made a
lot of progress in the last weak clearing away the layers of overgrowth
that have gotten in the way of seeing a clear story. Here's my summary
of what's been cleared away. (Reminder: this is the summary thread, so
its for summary information only, if you want to argue with the specific
points I'm making, take it to the right thread.)
Totality and patterns. I think it's even more obvious at this point
that the only realistic interpretation of `T t` as a pattern is that it
is total on `T`, including null. Anything else adds value-destroying
complexity when we try to compose patterns. But, it was hard to see
this because ...
Nullity and switch. We came at this with the mistaken assumption that
"switches are just null-hostile." But that was wrong. After digging at
it, we realized that the null-hostility of switch was an artifact of the
limited domains to which switch had been originally applied. When we
zoom out, it becomes obvious that the null-hostility of switch is not
scalable (we even tried to distort the semantics of patterns to try to
accomodate it.) The obvious move here is:
- Allow `case null` in all reference switches, with the obvious semantics;
- Enums, strings, and boxes get an implicit `case null: throw` at the
top if there is no explicit `case null`;
- Total patterns -- including default -- match null
So this means that _all_ switches are nullable, but these special target
types bring their own special null defaults. While we first thought it
might be the switch that was throwing, and then we thought maybe it was
the (possibly implicit) default that was throwing, in reality, it is the
invisible `case null` that comes with switching on these special types.
(Meta: this shows how much damage the "blow early, blow often" rule does
-- by introducing ad-hoc rules to try to create a null-free playing
field, trying to undo even one of these can take weeks of analysis to
unravel.)
These two moves clear away almost all of the null hazards with switch,
and put us on a principled foundation: with the exception of the legacy
switch types, null is just another value that flows through patterns and
switches, which can be matched, with the obvious and now-composible
semantics. I think this also should reduce the "totality is too subtle"
concern, because we've put the null hostility into a more well-defined
"box" -- switches are just nullable, so *of course* the nulls flow into
the total pattern.
Separately, there are TWO issues regarding switch totality. The first
is how we can give statement switches the same error checking for
totality that statement switches currently enjoy. I think there is npw
room to cleanly repurpose `default` for this.
The second is, while tangentially related to nullity, is about
_optimistic totality_. The optimistic totality we embraced in
expression switches over enums does not scale quite cleanly yet to
sealed types, and specifically to _lifting_ type patterns over sealed
types. We have more work to do here.
(One of the underappreciated moves of the optimistic totality we did in
12 is that it is _better_ to leave out the default clause when a switch
is believed to be optimistically total, because it leads to better type
checking -- omissions and separate compilation artifacts are detected at
compile time rather than runtime. We would like to get the same for
sealing.)
So, summary:
- Type patterns `T t` are total on U <: T, and `var t` is total on all
types;
- Total patterns match null;
- switches are not null hostile;
- `default` is a total switch case;
- you can say `case null` in switch;
- For switches on *enums, strings, and boxes*, there is an implicit
`case null` that throws, but you can override this with an explicit
`case null`. (There's still some fine points to discuss here; if we
want `case null` to be able to fall into default, then we can't require
it be at the top.)
- We can consider enhancing `default` to take a total destructuring
pattern with minimal distortion;
- We need to have a longer conversation about optimistic totality.
I think that's good progress for the week, as it checks off 3 of the
items on this list.
On 8/14/2020 1:19 PM, Brian Goetz wrote:
> Here's a summary of the issues raised in the reviews of the
> patterns-in-switch document. I'm going to (try to) start a new thread
> for each of them; let's not reply to this one with new topics (or with
> discussion on these topics.) I'll update this thread as we add or
> remove things from the list.
>
> - 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.
>
> - Guards. (John, Tagir) There is acknowledgement that some sort of
> "whoops, not this case" support is needed in order to maintain switch
> as a useful construct in the face of richer case labels, but some
> disagreement about whether an imperative statement (e.g., continue) or
> a declarative guard (e.g., `when <predicate>`) is the right choice.
>
> - Exhaustiveness and null. (Tagir) For sealed domains (enums and
> sealed types), we kind of cheated with expression switches because we
> could count on the switch filtering out the null. But Tagir raises an
> excellent point, which is that we do not yet have a sound definition
> of exhaustiveness that scales to nested patterns (do Box(Rect) and
> Box(Circle) cover Box(Shape)?) This is an interaction between sealed
> types and patterns that needs to be ironed out. (Thanks Tagir!)
>
> - Switch and null. (Tagir, Kevin) Should we reconsider trying to
> rehabilitate switches null-acceptance? There are several who are
> questioning whether this is trying to push things too far for too
> little benefit.
>
> - Rehabilitating default. The current design leaves default to rot;
> it is possible it has a better role to play with respect to the
> rehabilitation of switch, such as signalling that the switch is total.
>
> - Restrictions on instanceof. It has been proposed that we restrict
> total patterns from instanceof to avoid confusion; while no one has
> really objected, a few people have expressed mild discomfort. Leaving
> it on the list for now until we resolve some of the other nullity
> questions.
>
> - Meta. (Brian) Nearly all of this is about null. Is it possible
> that everything else about the proposal is so perfect that there's
> nothing else to talk about? Seems unlikely. I recommend we turn up
> the attenuation knob on nullity issues to leave some oxygen for some
> of the other flowers.
>
>
More information about the amber-spec-observers
mailing list