[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