Draft JLS Spec about unnamed patterns and variables

Brian Goetz brian.goetz at oracle.com
Wed Feb 22 17:04:05 UTC 2023


Good point (though I'd be wary of extrapolating too much from multicatch.)

I think the discussion Aggelos was looking to stimulate is the one that 
leads to a more principled understanding of when we should and should 
not try to detect dead patterns.  There's no limit to what we *could* 
do, but we don't want to make these decisions on the basis of "hey, we 
could have an error here, cool", nor do we want to set in motion an 
endless whack-a-mole of "we complain about X, and X is like Y, but we 
don't complain about Y."

The treatment of "domination" to detect dead cases is new with pattern 
matching (previously the only dead cases where "used the same constant 
twice".)  So to some extent we are left extrapolating from very little 
actual data.

We do detect "same constant twice" even in lists:

     switch (i) {
         case 1, 2 -> ...
         case 2, 3 -> ...   // duplicate label
     }

But I'm not sure we want to bootstrap our way from that into trying too 
hard to detect impossible cases.  For example, suppose we had range 
patterns:

     switch (i) {
         case 1: ...
         case 10: ...
         case 2..<=9: ...
         case 1..10: // dead
     }

Would we expect the compiler to do this analysis?




On 2/22/2023 11:07 AM, Remi Forax wrote:
>
>
> ------------------------------------------------------------------------
>
>     *From: *"Brian Goetz" <brian.goetz at oracle.com>
>     *To: *"Tagir Valeev" <amaembo at gmail.com>, "Angelos Bimpoudis"
>     <angelos.bimpoudis at oracle.com>
>     *Cc: *"amber-spec-experts" <amber-spec-experts at openjdk.java.net>
>     *Sent: *Wednesday, February 22, 2023 4:45:38 PM
>     *Subject: *Re: Draft JLS Spec about unnamed patterns and variables
>
>     It's a tricky question, because there's lots of ways to come at
>     it.  For example, we do make a distinction between dead
>     *statements* and dead code in general, and in particular
>     conditionals can have lots of dead code.
>
>     For example, in
>
>         if (true || destroyTheWorld()) { ... }
>
>     we don't remark that `destroyTheWorld()` is dead code (though fine
>     IDEs will call our attention with tasteful highlighting).  We're
>     pretty aggressive about avoiding _unreachable statements_, but
>     considerably less aggressive about dead code in general.
>
>     Thought experiment: what if we had union type patterns? Then the
>     case label `case String _, Integer _` would be like matching the
>     the union type pattern `(String|Integer) _`:
>
>         case Number n: ...
>         case (String|Integer) _: ...
>
>     Would javac then complain that `String|Integer` could be
>     simplified to just `String` on the bsais of flow analysis? 
>     (IntelliJ would, of course.) 
>
>
> At least, the compiler complains in a try/catch, by example
>
> try {
>   ioCall();
> } catch(IOException e) {
>   ...
> } catch(FileNotFoundException | RuntimeException e) {
>  ...
> }
>
> does not compile.
>
>
>     I initially thought as Tagir did, but then Gavin turned me around
>     and reminded me that it was not dead code, but unreachable
>     statements that we try to avoid.  So now I am torn...
>
>
> Rémi
>
>
>
>     On 2/22/2023 10:26 AM, Tagir Valeev wrote:
>
>         Hello!
>
>         I think we should consider dead patterns as dead code, so this
>         sample should not compile.
>
>         With best regards,
>         Tagir Valeev
>
>         On Wed, Feb 22, 2023, 15:34 Angelos Bimpoudis
>         <angelos.bimpoudis at oracle.com> wrote:
>
>             Coming back to the topic of dominance for a moment before
>             I circulate a revised draft spec.
>
>             Dominance is the way of pattern matching to detect/dead
>             code/(meaning that code on the RHS of a dominated case
>             will never be executed, provably).
>
>             Assume the example where|Number|dominates|Integer|--all
>             values of|Integer|are going to be matched by a proceeding
>             case,|Number|. This is a compile-time error. Additionally
>             notice that all binding variables happen to be unused.
>
>             |switch (o) {       case Number n -> 1;       case String
>             s -> 2;       case Integer i -> 2; } |
>
>             Under this JEP this code could be rewritten blindly into:
>
>             |switch (o) {       case Number _ -> 1;       case String
>             _, Integer _-> 2; } |
>
>             Under the definition of dead code above, the common case
>             that was grouped together,|-> 2|, is not dead anymore. It
>             can be reached via|*case String _*, Integer _-> 2|. As a
>             result, the code above is correct. It just happens that
>             the sub-pattern|Integer _|will never be reachable. This
>             can be a warning but the overall case is correct.
>
>             An alternative interpretation would be to treat
>             sub-patterns as "dead code". Under that interpretation the
>             second|case|of the second example would be dominated
>             because there is at least one preceding sub-pattern (or
>             whole case label with one pattern as in this case) that
>             dominates at least one of its sub-patterns (|Integer _|).
>             That case could be rejected (symmetrically to the first
>             example). This seems restrictive but also a valid direction.
>
>             So, my question is what would be the pros and cons of each
>             approach?
>
>
>             Many, thanks,
>
>             Aggelos
>
>
>             ------------------------------------------------------------------------
>             *From:* Brian Goetz <brian.goetz at oracle.com>
>             *Sent:* 26 January 2023 20:33
>             *To:* Angelos Bimpoudis <angelos.bimpoudis at oracle.com>;
>             amber-spec-experts <amber-spec-experts at openjdk.java.net>
>             *Subject:* Re: Draft JLS Spec about unnamed patterns and
>             variables
>             Small wording nit...  in "an unnamed declaration can be
>             used in place of the following declarations"
>
>             I'm not sure "in place of" is the right wording; I think
>             you may just want to say "in", since the grammar permits
>             it in all of these places.  (What you're really doing here
>             is signalling that there are places the grammar allows it,
>             but the semantics do not; you are going to call these out
>             individually in the appropriate places.)
>
>             Similar for the second "in place of" in this section.
>
>             In 14.11.1, I might refactor the text a little further. 
>             The second sentence of the first paragraph below is about
>             case constants only, but now comes after you talk about
>             case patterns or case constants:
>
>                 A|case|label has either one or more|case|constants,
>                 ora*one or more*|case|pattern*s*. Every|case|constant
>                 must be either (1) the|null|literal, (2) a constant
>                 expression (15.29
>                 <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.29>),
>                 or (3) the name of an enum constant (8.9.1
>                 <https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.9.1>);
>                 otherwise a compile-time error occurs. A|case|label
>                 that has a|null||case|constant may have an
>                 optional|default|.
>
>                 It is a compile-time error if for any|case|label with
>                 more than one|case|patterns, any of its|case|patterns
>                 declares one or more pattern variables.
>
>
>             I suggest:
>
>             A|case|label has either one or more|case|constants,
>             ora*one or more*|case|pattern*s*.
>
>             /For a case label with case constants,
>             /every|case|constant must be either (1) the|null|literal,
>             (2) a constant expression (15.29
>             <https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.29>),
>             or (3) the name of an enum constant (8.9.1
>             <https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.9.1>);
>             otherwise a compile-time error occurs. A|case|label that
>             has a|null||case|constant may have an optional|default|.
>
>             /For a case label with case patterns/, it is a
>             compile-time error if any of its|case|patterns declares
>             one or more pattern variables.
>
>             I am not sure about the definition of dominance here.  If
>             I have:
>
>                 case Integer _, String _:  A;
>                 case Number _ : B;
>
>             Number dominates Integer, but it doesn't dominate
>             Integer|String.  I think you mean "if at least one of
>             pi..pn dominates *all* of the patterns ri..rm, no?
>
>             But I'm not even sure if this is the right formulation,
>             because:
>
>                 sealed interface I permits A, B { }
>                 record A() implements I {}
>                 record B() implements I {}
>
>                 case A _, B _: ...
>                 case I i: ...
>
>             The first case label dominates I.  So I think you have to
>             appeal to exhaustiveness:
>
>             "A case label with case patterns p1...pm dominates another
>             case label with case patterns q1...qm if the set of
>             patterns { p1..pm } dominates each qi", no?
>
>             You probably have to slightly refactor the second
>             statement about "compile time error if dominance" accordingly.
>
>
>
>
>             On 1/26/2023 5:36 AM, Angelos Bimpoudis wrote:
>
>                 Dear experts,
>
>                 The first draft of the JLS spec about unnamed patterns
>                 and variables (https://openjdk.org/jeps/8294349) is
>                 available at:
>
>                 https://cr.openjdk.java.net/~abimpoudis/unnamed/latest/
>
>                 Comments very much welcomed!
>                 Angelos
>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/amber-spec-observers/attachments/20230222/401754e5/attachment-0001.htm>


More information about the amber-spec-observers mailing list