On 28/04/2021 17:29, Brian Goetz wrote:
I assume that you are saying Box permits Soup only. But your
assumptions about "where do the nulls go" here are not right.
Box(Soup) does not match Box(null); the set of patterns { Box(Soup) }
is total on Box(Lunch) _with remainder Box(null)_. So the null paths
in this example are dead. (Also missing break statements.) So
rewriting, this switch is really equivalent to:
switch (lunch) {
case Box(Soup s):
System.err.println("Box of soup");
break;
case Bag(Soup s):
System.err.println("Bag of soup");
break;
/* implicit */
case Box(null), Bag(null): throw new NPE();
}
and the switch is total on Container(Lunch) under the Lunch=Soup,
Container=Box|Bag assumptions.
I have to admit that this is surprising.
So, if I have a sealed hierarchy that only permits one concrete type:
interface Foo permits Bar
doing:
Foo x = ...
if (x instanceof Bar)
is not considered a total instanceof?
Maurizio