On 28/04/2021 00:44, Remi Forax wrote:


------------------------------------------------------------------------

    *De: *"Maurizio Cimadamore" <maurizio.cimadam...@oracle.com>
    *À: *"Brian Goetz" <brian.go...@oracle.com>, "amber-spec-experts"
    <amber-spec-experts@openjdk.java.net>
    *Envoyé: *Mardi 27 Avril 2021 16:23:20
    *Objet: *Re: Switch labels (null again), some tweaking


    On 23/04/2021 16:38, Brian Goetz wrote:

        So, I think the "a switch only accepts null if the letters
        n-u-l-l are present", while a comforting move in the short
        term, buys us relatively little, and dulls our pain receptors
        which in turn makes it take way longer to learn how patterns
        really work.  I think we should go back to:

         - A switch accepts null if (a) one of the case labels is
        `null` or (b) the switch has a total pattern (which must
always be the last case.)
    The proposal seems ok; it does nothing for the problem I'm
    concerned about (e.g. type of the target expression changing and
    influencing the totality analysis at a distance) - but that was
    not address by the previous proposal either (as you say in your
    email, admittedly, I was reading too much into your proposal).


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


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

    Stepping back - my general feeling on this topic is that the
    audience in this mailing list have a very intimate knowledge of
    what a "total pattern" is, to the point that they are comfortable
    building on top of this definition to e.g. define null behavior of
    patterns. I'm a little afraid that the finer detail of totality
    might be lost on the average Joe developer: totality is a much
    more slippery concept than it seems. Sure, there is one obvious
    way to make your pattern total: if the target expression has type
    E, then add a type test pattern whose type is also E. That seems
    easy enough. Except that, the type of E will not always be that
    manifest in user code (e.g. might be the result of what javac
    happens to infer on Tuesdays). And, if you mix this with sealed
    classes, it might be possible for a switch to go from total to
    non-total, as new permitted subtypes are added to a sealed
    hierarchy. These might all be all corner cases - but I think it's
    this complexity which contributes to my "isn't this all too
    subtle?" feeling.

    Obviously I'm well aware that nearly every path has been explored,
    and no silver bullet seems to be laying around, so... this might
    just be the best we can offer, and that's ok.


We tried to have a way to signal that a pattern is total or not, by example, using a keyword, like total or default, but it did not work well when a pattern is partially total like "case Foo(true, var x)"

Yep - I'm aware of the various roads not taken - I'm not suggesting that there's some shiny great solution which is better than what is being proposed; I just wanted to air my concerns about the complexity of the programming model implied in this proposal. In other cases (DA/DU, scoping of pattern variables and, to a certain degree type inference, esp. after Java 8) the rules are mind-blowingly complex, but developers can form an intuitive notion of how these things work, and trust the compiler to do the right thing - e.g. these features, despite their complexity are mostly out of your face, and when the compiler barks, the user will have some idea of what went wrong (whooops, uninitialized final variable here!). Totality analysis is not as complex as some of the features mentioned above - but it is something that users will have to think about in the back of their minds, when reasoning about how their pattern switches work.

Maurizio



    Cheers
    Maurizio


Rémi

Reply via email to