At least, if you want a total type, you can make it explicit using
case var x
which is always total whatever the type switched upon.
So you have two tools to avoid influence at distance in the totality
analysis,
- for a switch where you can enumerate all the values enums, sealed
type (boolean should be in that category too IMO, but we did not
agree on that), if you list all the possible cases, a total case is
not required.
Without changes to switch, there is nothing which would break if a
"new case" is added (to the enum, or to the sealed hierarchy). So,
listing "all possible cases" relies on the assumption that you know
what "all cases" are. And right now there's no way to declaratively
say: this switch (statement) is gonna cover them all. Brian answer
goes a bit in that direction, which is good, for the outermost layer
(but the problem still exists somewhat at the nested level).
It depends on how much sealing there is. Suppose we have sealed types
Container = Box|Bag and Lunch=Soup|Sandwich. If we are switching on a
Container<Lunch>:
switch (lunch) {
case Box(Soup s):
case Box(Sandwich s):
case Bag(Soup s):
case Bag(Sandwich s):
}
This switch is exhaustive because:
- { Soup, Sandwich } is total on on Lunch (with remainder null)
- therefore { Box(Soup), Box(Sandwich) } is total on Box<Lunch> (with
remainder null, Box(null) }
- similarly { Bag(Soup), Bag(Sandwich) } is total on Bag<Lunch> (with
remainder null, Bag(null) }
- { Box, Bag } is total on Container (with remainder null)
- therefore the cases in our switch are exhaustive on Container<Lunch>
If Lunch were not sealed, the compiler would complain, and we'd need
extra cases to get totality on Box and on Bag, which is needed to get
totality on Container:
switch (lunch) {
case Box(Soup s):
case Box(Sandwich s):
case Box(var s):
case Bag(Soup s):
case Bag(Sandwich s):
case Bag(var s):
}
So I think its similar at every level. And you can say `var` or `Lunch`
or `Object`; they're all total in this context.
- use "var" so the total case is explicit, "case var x", "case
Foo(var x)", etc
Sure - this is a good solution. One minor annoying thing is that we
started from a position where we said "var is just for inference" and
now we're back in a place where, while var is still, conceptually at
least, about inference, developers will also be using it for totality
(as inference guarantees that you are always 100% covered).
No, you can also say `case Object x` or `case Foo(Object x)` and be
semantically equivalent. Var is just type inference here; Remi is
saying "if you don't want to think about what types are total, say var,
and you'll be right." But its just inference for "the minimal type that
is total."