Draft JLS Spec about unnamed patterns and variables

Brian Goetz brian.goetz at oracle.com
Wed Feb 22 15:45:38 UTC 2023


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

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



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/8ceae9cd/attachment-0001.htm>


More information about the amber-spec-observers mailing list