[pattern-switch] Opting into totality
Brian Goetz
brian.goetz at oracle.com
Fri Sep 4 18:06:50 UTC 2020
> I bring this up again not to defend the syntax, but to underscore a
> more important point: that we thought at first that “sealing” switches
> was about asserting totality and enlisting the compiler’s aid in
> verifying same, but as we worked through the cases, and discovered
> there were more cases of remainder than we initially thought, the main
> value of sealing instead became restoring the switch to having no
> unhandled remainder. Whatever syntax we choose should try to evoke
> that at least as much as evoking totality of the case labels.
Taking this a little further: it is not that interesting to declare a
switch `sealed` that has a default clause or other total pattern; such
switches are "obviously" total and non-leaky. It's nice, but we
wouldn't add a language feature for it.
The interesting part of sealing a switch are cases like this. Assume
Shape = Circ | Rect.
switch (shape) {
case Circ c:
case Rect r:
}
Here, sealing gives us two things: asserting we've covered all the cases
(which is not going to be obvious except in the most trivial of sealed
types) and handling of remainder (here, only null.) Similarly:
switch (boxOfShape) {
case Box(Circ c):
case Box(Rect r):
}
Same basic story -- not obvious that we've covered all boxes, the
remainder is just slightly more complicated.
The compile-time checking for optimistic totality, and runtime checking
for remainder, are two sides of the same coin; we are stating
expectations that all possible inputs are covered, either by an explicit
case or by an implicit remainder case. We statically check the ones we
can, and dynamically reject the "acceptable non-coverage."
(Characterizing the acceptable non-coverage is the main bit of positive
progress we've made recently.)
I think we may be skipping over a step by jumping to "throwing syntax at
the problem." The real question is, what do we want the users thinking
about when they are coding, and what should we not be bothering them
with? We've already acknowledged that we _don't_ want them worrying
about explicitly managing the remainder.
We've been approaching this as "I assert that this switch is
sufficiently total", which included both strongly total and
optimistically total switches (because that's what we already do for
expression switches.) But given that having a default case makes it
obviously total (and obviates the need for remainder handling), perhaps
we want to focus on the user asserting "I know I didn't write a default,
but I am still covering all the cases." Does that offer a different
enough viewpoint that other options come into focus?
More information about the amber-spec-experts
mailing list