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."


Reply via email to