Draft JLS Spec about unnamed patterns and variables

Remi Forax forax at univ-mlv.fr
Wed Feb 22 16:07:27 UTC 2023


> 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 < [
>> mailto:angelos.bimpoudis at oracle.com | 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 < [ mailto:brian.goetz at oracle.com | brian.goetz at oracle.com ] >
>>> Sent: 26 January 2023 20:33
>>> To: Angelos Bimpoudis < [ mailto:angelos.bimpoudis at oracle.com |
>>> angelos.bimpoudis at oracle.com ] >; amber-spec-experts < [
>>> mailto:amber-spec-experts at openjdk.java.net |
>>> 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, or a one or more case
>>>> pattern s . Every case constant must be either (1) the null literal, (2) a
>>>> constant expression ( [
>>>> https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.29 |
>>>> 15.29 ] ), or (3) the name of an enum constant ( [
>>>> https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.9.1 | 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, or a 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 ( [
>>> https://docs.oracle.com/javase/specs/jls/se19/html/jls-15.html#jls-15.29 |
>>> 15.29 ] ), or (3) the name of an enum constant ( [
>>> https://docs.oracle.com/javase/specs/jls/se19/html/jls-8.html#jls-8.9.1 | 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 | https://openjdk.org/jeps/8294349 ] ) is
>>>> available at:

>>>> [ https://cr.openjdk.java.net/~abimpoudis/unnamed/latest/ |
>>>> 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/f84d7bd1/attachment-0001.htm>


More information about the amber-spec-observers mailing list