From cushon at google.com Mon Aug 2 17:34:07 2021 From: cushon at google.com (Liam Miller-Cushon) Date: Mon, 2 Aug 2021 10:34:07 -0700 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> Message-ID: On Sat, Jul 31, 2021 at 12:51 PM Brian Goetz wrote: > > Another option that gets some of the benefit and doesn't require a > > spec change is to omit the reference to the enclosing instance if it > > is unused. We've been doing that successfully for a few years at > > Google. There was some minor compatibility impact to code using > > reflection to access the synthetic field that stores the reference to > > the enclosing instance, but that was very rare, and the benefit is > > that it avoids some memory leaks. > > The people who would complain are in a pretty weak position: > > - The field is private and synthetic; you shouldn't be reflecting on > it at all; > - The field name is an implementation detail of the compiler, and not > specified, so you shouldn't even pretend you know its name; > - If its your class, the easy thing to do is add an accessor, so the > only people who would complain are those that are breaking into classes > they don't control. > > I think it is reasonable for the language to infer whether the enclosing > instance is "captured" by the inner class or not, and that's consistent > with how lambdas behave. > Thanks, that all sounds right to me. I filed https://bugs.openjdk.java.net/browse/JDK-8271623 to track that enhancement. From brian.goetz at oracle.com Mon Aug 2 18:18:56 2021 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 2 Aug 2021 14:18:56 -0400 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> Message-ID: FWIW, making this fix not only reduces the memory leak risk, but has a number of nice follow-on benefits that can often trigger further follow-on benefits: ?- fewer fields, so reduced footprint; ?- fewer fields might mean more objects fall under the scalarization threshold, when applicable; ?- less work in constructors; ?- shorter constructors mean more constructors fall under the inlining threshold; ?- more inlining might lead to other optimizations. So it wouldn't surprise me to see macro-level effects even on programs without memory leaks. > I filed https://bugs.openjdk.java.net/browse/JDK-8271623 > to track that > enhancement. From brian.goetz at oracle.com Mon Aug 2 19:26:04 2021 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 2 Aug 2021 15:26:04 -0400 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> Message-ID: <5f446027-31e9-1a9c-9b6c-22400d722b5b@oracle.com> I am happy to see this move forward as an ordinary RFE, though it would be good to do some corpus searches for `this$0` to gauge how broadly the assumption that inner classes always have this field is. On 8/2/2021 1:34 PM, Liam Miller-Cushon wrote: > On Sat, Jul 31, 2021 at 12:51 PM Brian Goetz > wrote: > > > Another option that gets some of the benefit and doesn't require a > > spec change is to omit the reference to the enclosing instance > if it > > is unused. We've been doing that successfully for a few years at > > Google. There was some minor compatibility impact to code using > > reflection to access the synthetic field that stores the > reference to > > the enclosing instance, but that was very rare, and the benefit is > > that it avoids some memory leaks. > > The people who would complain are in a pretty weak position: > > ??- The field is private and synthetic; you shouldn't be > reflecting on > it at all; > ??- The field name is an implementation detail of the compiler, > and not > specified, so you shouldn't even pretend you know its name; > ??- If its your class, the easy thing to do is add an accessor, so > the > only people who would complain are those that are breaking into > classes > they don't control. > > I think it is reasonable for the language to infer whether the > enclosing > instance is "captured" by the inner class or not, and that's > consistent > with how lambdas behave. > > > Thanks, that all sounds right to me. > > I filed https://bugs.openjdk.java.net/browse/JDK-8271623 > to track that > enhancement. From forax at univ-mlv.fr Mon Aug 2 19:46:24 2021 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 2 Aug 2021 21:46:24 +0200 (CEST) Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> Message-ID: <1699135460.215325.1627933584253.JavaMail.zimbra@u-pem.fr> We may have some trouble with the usual suspect, Serialization, There are classes like exceptions or Swing UI classes that are marked as Serializable and can be implemented as an anonymous class. In that case, removing the backpointer if it is not used may change the serialization format. And yes, an anonymous class do not have a "stable" name but people do not seem to care too much about that ... R?mi ----- Original Message ----- > From: "Brian Goetz" > To: "Liam Miller-Cushon" > Cc: "Remi Forax" , "John Rose" , "amber-spec-experts" > > Sent: Lundi 2 Ao?t 2021 20:18:56 > Subject: Re: [External] : Re: Minor improvement to anonymous classes > FWIW, making this fix not only reduces the memory leak risk, but has a > number of nice follow-on benefits that can often trigger further > follow-on benefits: > > ?- fewer fields, so reduced footprint; > ?- fewer fields might mean more objects fall under the scalarization > threshold, when applicable; > ?- less work in constructors; > ?- shorter constructors mean more constructors fall under the inlining > threshold; > ?- more inlining might lead to other optimizations. > > So it wouldn't surprise me to see macro-level effects even on programs > without memory leaks. > >> I filed https://bugs.openjdk.java.net/browse/JDK-8271623 >> to track that > > enhancement. From amaembo at gmail.com Tue Aug 3 04:52:45 2021 From: amaembo at gmail.com (Tagir Valeev) Date: Tue, 3 Aug 2021 11:52:45 +0700 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: <1699135460.215325.1627933584253.JavaMail.zimbra@u-pem.fr> References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> <1699135460.215325.1627933584253.JavaMail.zimbra@u-pem.fr> Message-ID: Another possible semantics change is the object lifetime. The code might rely on prolonged lifetime of the surrounding object if there are soft/weak/phantom references. E.g., the outer object might be registered via Cleaner, and the change may cause freeing the resource earlier than expected. Likely, this is a very rare scenario but if it happens, it could be quite hard to identify the root cause, as the problem will appear only if the object is collected within the specific timeframe. By the way, are we speaking about anonymous classes only? I think, local classes could be updated in the similar manner. Especially given the fact that now local records don't capture the surrounding "this" but if we convert the record to an equivalent local class, it will capture: public class Test { void test() { record R() {} // does not capture Test instance class C {} // captures Test instance } } Or should we allow explicit 'static' modifier on local classes? Best regards, Tagir Valeev. On Tue, Aug 3, 2021 at 2:47 AM wrote: > > We may have some trouble with the usual suspect, Serialization, > There are classes like exceptions or Swing UI classes that are marked as Serializable and can be implemented as an anonymous class. > In that case, removing the backpointer if it is not used may change the serialization format. > > And yes, an anonymous class do not have a "stable" name but people do not seem to care too much about that ... > > R?mi > > ----- Original Message ----- > > From: "Brian Goetz" > > To: "Liam Miller-Cushon" > > Cc: "Remi Forax" , "John Rose" , "amber-spec-experts" > > > > Sent: Lundi 2 Ao?t 2021 20:18:56 > > Subject: Re: [External] : Re: Minor improvement to anonymous classes > > > FWIW, making this fix not only reduces the memory leak risk, but has a > > number of nice follow-on benefits that can often trigger further > > follow-on benefits: > > > > - fewer fields, so reduced footprint; > > - fewer fields might mean more objects fall under the scalarization > > threshold, when applicable; > > - less work in constructors; > > - shorter constructors mean more constructors fall under the inlining > > threshold; > > - more inlining might lead to other optimizations. > > > > So it wouldn't surprise me to see macro-level effects even on programs > > without memory leaks. > > > >> I filed https://bugs.openjdk.java.net/browse/JDK-8271623 > >> to track that > > > enhancement. From john.r.rose at oracle.com Tue Aug 3 05:06:20 2021 From: john.r.rose at oracle.com (John Rose) Date: Tue, 3 Aug 2021 05:06:20 +0000 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> , <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> Message-ID: <84BDB1D8-1372-4F3F-8CF4-A31E50959E76@oracle.com> +1 on removing unused this$1 > On Jul 31, 2021, at 12:51 PM, Brian Goetz wrote: > > ? > >> Another option that gets some of the benefit and doesn't require a spec change is to omit the reference to the enclosing instance if it is unused. We've been doing that successfully for a few years at Google. There was some minor compatibility impact to code using reflection to access the synthetic field that stores the reference to the enclosing instance, but that was very rare, and the benefit is that it avoids some memory leaks. > > The people who would complain are in a pretty weak position: > > - The field is private and synthetic; you shouldn't be reflecting on it at all; > - The field name is an implementation detail of the compiler, and not specified, so you shouldn't even pretend you know its name; > - If its your class, the easy thing to do is add an accessor, so the only people who would complain are those that are breaking into classes they don't control. > > I think it is reasonable for the language to infer whether the enclosing instance is "captured" by the inner class or not, and that's consistent with how lambdas behave. From forax at univ-mlv.fr Tue Aug 3 07:56:35 2021 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 3 Aug 2021 09:56:35 +0200 (CEST) Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> <1699135460.215325.1627933584253.JavaMail.zimbra@u-pem.fr> Message-ID: <858345338.335766.1627977395597.JavaMail.zimbra@u-pem.fr> ----- Original Message ----- > From: "Tagir Valeev" > To: "Remi Forax" > Cc: "Brian Goetz" , "Liam Miller-Cushon" , "John Rose" > , "amber-spec-experts" > Sent: Mardi 3 Ao?t 2021 06:52:45 > Subject: Re: [External] : Re: Minor improvement to anonymous classes [...] > > By the way, are we speaking about anonymous classes only? I think, > local classes could be updated in the similar manner. yes, it's what Liam's patch does. > Especially given the fact that now local records don't capture the surrounding "this" > but if we convert the record to an equivalent local class, it will > capture: > > public class Test { > void test() { > record R() {} // does not capture Test instance > class C {} // captures Test instance > } > } > > Or should we allow explicit 'static' modifier on local classes? For me, the behavior of local classes and anonymous classes should be aligned as the patch of Liam does, and we should still allow static on local classes if someone want to document that behavior in his code. > > Best regards, > Tagir Valeev. regards, R?mi > > On Tue, Aug 3, 2021 at 2:47 AM wrote: >> >> We may have some trouble with the usual suspect, Serialization, >> There are classes like exceptions or Swing UI classes that are marked as >> Serializable and can be implemented as an anonymous class. >> In that case, removing the backpointer if it is not used may change the >> serialization format. >> >> And yes, an anonymous class do not have a "stable" name but people do not seem >> to care too much about that ... >> >> R?mi >> >> ----- Original Message ----- >> > From: "Brian Goetz" >> > To: "Liam Miller-Cushon" >> > Cc: "Remi Forax" , "John Rose" , >> > "amber-spec-experts" >> > >> > Sent: Lundi 2 Ao?t 2021 20:18:56 >> > Subject: Re: [External] : Re: Minor improvement to anonymous classes >> >> > FWIW, making this fix not only reduces the memory leak risk, but has a >> > number of nice follow-on benefits that can often trigger further >> > follow-on benefits: >> > >> > - fewer fields, so reduced footprint; >> > - fewer fields might mean more objects fall under the scalarization >> > threshold, when applicable; >> > - less work in constructors; >> > - shorter constructors mean more constructors fall under the inlining >> > threshold; >> > - more inlining might lead to other optimizations. >> > >> > So it wouldn't surprise me to see macro-level effects even on programs >> > without memory leaks. >> > >> >> I filed https://bugs.openjdk.java.net/browse/JDK-8271623 >> >> to track that > > > > enhancement. From brian.goetz at oracle.com Tue Aug 3 12:41:33 2021 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 3 Aug 2021 08:41:33 -0400 Subject: [External] : Re: Minor improvement to anonymous classes In-Reply-To: References: <424ad976-6f0c-5ada-ca22-f5a3d9c76dc1@oracle.com> <2ED211EA-3F96-4129-B5BF-9A262C917D9F@oracle.com> <1320762308.901257.1627755887681.JavaMail.zimbra@u-pem.fr> <32bade08-4697-a2fd-52d2-491822c14d19@oracle.com> <1699135460.215325.1627933584253.JavaMail.zimbra@u-pem.fr> Message-ID: <49676f3c-100e-ccb1-ee9a-ef999f9f4a0d@oracle.com> Yes, local classes too.? Essentially, this is for translation of "effectively static" inner classes. I think this is independent of explicit-static or not; explicit-static allows the programmer to capture intent and get more type checking as a result.? This is about generating better code. On 8/3/2021 12:52 AM, Tagir Valeev wrote: > Another possible semantics change is the object lifetime. The code > might rely on prolonged lifetime of the surrounding object if there > are soft/weak/phantom references. E.g., the outer object might be > registered via Cleaner, and the change may cause freeing the resource > earlier than expected. Likely, this is a very rare scenario but if it > happens, it could be quite hard to identify the root cause, as the > problem will appear only if the object is collected within the > specific timeframe. > > By the way, are we speaking about anonymous classes only? I think, > local classes could be updated in the similar manner. Especially given > the fact that now local records don't capture the surrounding "this" > but if we convert the record to an equivalent local class, it will > capture: > > public class Test { > void test() { > record R() {} // does not capture Test instance > class C {} // captures Test instance > } > } > > Or should we allow explicit 'static' modifier on local classes? > > Best regards, > Tagir Valeev. > > On Tue, Aug 3, 2021 at 2:47 AM wrote: >> We may have some trouble with the usual suspect, Serialization, >> There are classes like exceptions or Swing UI classes that are marked as Serializable and can be implemented as an anonymous class. >> In that case, removing the backpointer if it is not used may change the serialization format. >> >> And yes, an anonymous class do not have a "stable" name but people do not seem to care too much about that ... >> >> R?mi >> >> ----- Original Message ----- >>> From: "Brian Goetz" >>> To: "Liam Miller-Cushon" >>> Cc: "Remi Forax" , "John Rose" , "amber-spec-experts" >>> >>> Sent: Lundi 2 Ao?t 2021 20:18:56 >>> Subject: Re: [External] : Re: Minor improvement to anonymous classes >>> FWIW, making this fix not only reduces the memory leak risk, but has a >>> number of nice follow-on benefits that can often trigger further >>> follow-on benefits: >>> >>> - fewer fields, so reduced footprint; >>> - fewer fields might mean more objects fall under the scalarization >>> threshold, when applicable; >>> - less work in constructors; >>> - shorter constructors mean more constructors fall under the inlining >>> threshold; >>> - more inlining might lead to other optimizations. >>> >>> So it wouldn't surprise me to see macro-level effects even on programs >>> without memory leaks. >>> >>>> I filed https://bugs.openjdk.java.net/browse/JDK-8271623 >>>> to track that >>>> enhancement. From forax at univ-mlv.fr Thu Aug 26 19:06:24 2021 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 26 Aug 2021 21:06:24 +0200 (CEST) Subject: Switch coverage with multiple branches In-Reply-To: <870F7B54-9A9E-414F-9A7B-D12DB33FB288@oracle.com> References: <870F7B54-9A9E-414F-9A7B-D12DB33FB288@oracle.com> Message-ID: <789155336.385900.1630004784590.JavaMail.zimbra@u-pem.fr> Here is another example with i believe the same issue sealed interface Vehicle {} record Car(String owner, String color) implements Vehicle {} record Bus(String owner) implements Vehicle {} public static void example2() { var vehicles = List.of( new Car("Bob", "red"), new Bus("Ana") ); for(var vehicle: vehicles) { switch(vehicle) { case Car car -> System.out.println("car !"); case Bus bus -> System.out.println("bus !"); case Record record -> throw new AssertionError(); } } } This code currently compiles even if the last case is not reachable. R?mi ----- Original Message ----- > From: "daniel smith" > To: "amber-spec-experts" > Cc: "Gavin Bierman" > Sent: Samedi 24 Juillet 2021 00:28:08 > Subject: Switch coverage with multiple branches > An RFE for JEP 406 (or maybe bug fix? I haven't dug into what the spec says). > Can we make this compile? > > public class SwitchCoverage { > sealed interface A {} > sealed interface B1 extends A {} > sealed interface B2 extends A {} > sealed interface C extends A {} > final class D1 implements B1, C {} > final class D2 implements B2, C {} > > void test(A arg) { > int i = switch (arg) { > case B1 b1 -> 1; > case B2 b2 -> 2; > }; > } > > } > > Output: > > % -> `javahome 17`/bin/javac --enable-preview --release 17 SwitchCoverage.java > SwitchCoverage.java:10: error: the switch expression does not cover all possible > input values > int i = switch (arg) { > ^ > Note: SwitchCoverage.java uses preview features of Java SE 17. > Note: Recompile with -Xlint:preview for details. > 1 error > > The compiler wants to see a 'case C c', not realizing that the combination of B1 > and B2 already covers C. > > The use case might seem a impractically complex, but I think it's actually > pretty normal to want to define a universe of values (that's A), provide some > implementations (D1 and D2), and then categorize the implementations in > different dimensions (B1/B2 in one dimension, C in another). When I'm writing > my switch, I might only care about one of these dimensions. From forax at univ-mlv.fr Sat Aug 28 21:42:38 2021 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 28 Aug 2021 23:42:38 +0200 (CEST) Subject: Revisiting the rule for merging type patterns ? Message-ID: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> I believe that the rule for merging type pattern is overly restrictive, here is an example of a method that collects all the declared variables (the language is a kind of functional JavaScript i'm using for teaching) private static void visitVariable(Expr expr, JSObject env) { switch (expr) { case Block block -> { for (Expr instr : block.instrs()) { visitVariable(instr, env); } } case Literal literal -> { // do nothing } case FunCall funCall -> { // do nothing } case LocalVarAssignment localVarAssignment -> { if (localVarAssignment.declaration()) { env.register(localVarAssignment.name(), env.length()); } } case LocalVarAccess localVarAccess -> { // do nothing } case Fun fun -> { // do nothing } case Return _return -> { // do nothing } case If _if -> { visitVariable(_if.trueBlock(), env); visitVariable(_if.falseBlock(), env); } case New _new -> { // do nothing } case FieldAccess fieldAccess -> { // do nothing } case FieldAssignment fieldAssignment -> { // do nothing } case MethodCall methodCall -> { // do nothing } default -> throw new AssertionError("unknown case " + expr.getClass()); }; } Here i can not group the cases that do nothing together because we have explicitly disallow it, so the code below does not compile case Literal literal, FunCall funcall -> { // do nothing } I think we should revisit that discussion and just not introduce the any bindings in that case so the example above will compile but "literal" or "funcall" are not added as local variable. Once we will introduce '_', the "correct" way to write such code will be case Literal _, FunCall _ -> { // do nothing } regards, R?mi From john.r.rose at oracle.com Sun Aug 29 01:25:26 2021 From: john.r.rose at oracle.com (John Rose) Date: Sun, 29 Aug 2021 01:25:26 +0000 Subject: Revisiting the rule for merging type patterns ? In-Reply-To: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> References: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> Message-ID: On Aug 28, 2021, at 2:42 PM, Remi Forax > wrote: I think we should revisit that discussion and just not introduce the any bindings in that case so the example above will compile but "literal" or "funcall" are not added as local variable. Some partial comments: Allowing inconsistent/inaccessible binding names here as a particular workaround would be a sharp edge, since users would wonder where such a variable went, and why they can?t use it. I think this is really a feature-request for a type-only pattern (with no binding). And having ?T _? is a fine way to bikeshed it. That said, the next feature request in that vein would be to allow variable-bindings (as today) for the sake of guard expressions, and then we are back to the problem you cite. Hmm? I guess the sharp edge has cause to stay, for the sake of guard logic like this: case Literal l && someGuard(l), FunCall f && someOtherGuard(f) -> ? So I?m sympathetic with your request. It?s really about smuggling OR-expressions into switch-guards. Which isn?t terrible at first. A third request in this vein is for combining bindings from arms of an OR-expression. That?s when it gets more terrible: case Literal lorf && decon1(l, n), FunCall lorf && decon2(f, n) -> { lorf is an intersection type, and maybe n is int if decon1/2 collude to make it so } Assembling one binding from several OR-branches seems to be a requitable feature, but one that would be really hard to make rational and predictable. ? John From forax at univ-mlv.fr Sun Aug 29 10:47:32 2021 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Sun, 29 Aug 2021 12:47:32 +0200 (CEST) Subject: Revisiting the rule for merging type patterns ? In-Reply-To: References: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> Message-ID: <1860168672.1065074.1630234052919.JavaMail.zimbra@u-pem.fr> > From: "John Rose" > To: "Remi Forax" > Cc: "amber-spec-experts" > Sent: Dimanche 29 Ao?t 2021 03:25:26 > Subject: Re: Revisiting the rule for merging type patterns ? > On Aug 28, 2021, at 2:42 PM, Remi Forax < [ mailto:forax at univ-mlv.fr | > forax at univ-mlv.fr ] > wrote: >> I think we should revisit that discussion and just not introduce the any >> bindings in that case so the example above will compile but "literal" or >> "funcall" are not added as local variable. > Some partial comments: > Allowing inconsistent/inaccessible binding names here > as a particular workaround would be a sharp edge, > since users would wonder where such a variable went, > and why they can?t use it. > I think this is really a feature-request for a type-only > pattern (with no binding). And having ?T _? is a fine way > to bikeshed it. > That said, the next feature request in that vein would be > to allow variable-bindings (as today) for the sake of guard > expressions, and then we are back to the problem you cite. > Hmm? I guess the sharp edge has cause to stay, for the sake > of guard logic like this: > case Literal l && someGuard(l), FunCall f && someOtherGuard(f) -> ? > So I?m sympathetic with your request. It?s really about > smuggling OR-expressions into switch-guards. Which isn?t > terrible at first. I see it as rehabilitating the OR-pattern. We use comma in between constants, we should be able to use comma in between patterns. I see a way to try to alleviate the issue of the inconsistent/inaccessible binding names, make the names available after the "->" but poison them so the names are accessible and/but javac emits a clear error message that those binding names are not available (we already does that in the initializer expression of a field). So case Literal literal && someGuard(literal), FunCall f && someOtherGuard(f) -> literal.foo() does not compile and javac can emit an error message on "literal.foo()" saying that binding names are not propagated through the OR-pattern. Obviously, it will still be weird the first time a user will try that but at least he will have an error message to google. > A third request in this vein is for combining bindings > from arms of an OR-expression. That?s when it gets > more terrible: > case Literal lorf && decon1(l, n), FunCall lorf && decon2(f, n) -> { > lorf is an intersection type, and maybe n is int > if decon1/2 collude to make it so > } > Assembling one binding from several OR-branches > seems to be a requitable feature, but one that would > be really hard to make rational and predictable. An intersection type is not very useful because you can only call methods that are available on a common super-type, so this is equivalent to case CommonSuperTypeOfLiteralAndFunCall lorf && decon3(lorf, n) -> ... It would be different if Java had a real way to OR types like Scala 3 (and Ceylon before). > ? John R?mi From forax at univ-mlv.fr Sun Aug 29 14:00:21 2021 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 29 Aug 2021 16:00:21 +0200 (CEST) Subject: switch expression with not explicit yield value should work ? Message-ID: <84434836.1074099.1630245621532.JavaMail.zimbra@u-pem.fr> Another case where the spec is weird, i've converted a project that generate a visitor from a grammar (something like yacc) to use a switch on type instead. Sometimes for a degenerate portion of the grammar i've an empty visitor that always throw an exception, the equivalent code with a switch is static Object result(Object o) { return switch (o) { case Object __ -> throw new AssertionError(); }; } Obviously i can tweak the code generator to generate static Object result(Object o) { throw new AssertionError(); } but not be able to compile the former code strike me as odd. An expression switch is a poly-expression, so the result type is back-propagated from the return type of the method result, so it should be Object. Moreover, if the switch is not a switch expression but a switch statement, the code is also valid static Object result(Object o) { switch (o) { case Object __ -> throw new AssertionError(); } } Not be able to compile a switch expression when there is no explicit result type but only an implicit type seems arbitrary to me (this change is backward compatible because it only makes more codes compiling). R?mi From amaembo at gmail.com Mon Aug 30 02:00:27 2021 From: amaembo at gmail.com (Tagir Valeev) Date: Mon, 30 Aug 2021 09:00:27 +0700 Subject: switch expression with not explicit yield value should work ? In-Reply-To: <84434836.1074099.1630245621532.JavaMail.zimbra@u-pem.fr> References: <84434836.1074099.1630245621532.JavaMail.zimbra@u-pem.fr> Message-ID: Hello! I think this is not related to recent JEPs. This behavior is standardised since Java 14 when Switch expression was introduced: // Compilation error int x = switch(0) { default -> throw new IllegalArgumentException(); }; This is explicitly specified (15.28.1) [1]: > It is a compile-time error if a switch expression has no result expressions. There was some discussion about this rule in March, 2019 [2]. Basically, the idea is to preserve the possibility of normal (non-abrupt) execution of every expression. I believe, preventing unreachable code has always been in the spirit of Java. In your code sample, the execution of the 'return' statement itself is unreachable, so writing 'return' is redundant. In my sample above, the 'x' variable is never assigned to anything, and the subsequent statements (if any) are unreachable as well. I'd vote to keep the current behavior. While it may complicate code generation and automatic refactorings, this additional complexity is only marginal. The benefit is that this behavior may save us from accidental mistakes. Btw, you may deceive the compiler introducing a method like static Object fail() { throw new IllegalArgumentException(); } And use "case Object __ -> fail()" With best regards, Tagir Valeev. [1] https://docs.oracle.com/javase/specs/jls/se16/html/jls-15.html#jls-15.28.1 [2] https://mail.openjdk.java.net/pipermail/amber-spec-experts/2019-March/001067.html On Sun, Aug 29, 2021 at 9:00 PM Remi Forax wrote: > > Another case where the spec is weird, > i've converted a project that generate a visitor from a grammar (something like yacc) to use a switch on type instead. > > Sometimes for a degenerate portion of the grammar i've an empty visitor that always throw an exception, > the equivalent code with a switch is > > static Object result(Object o) { > return switch (o) { > case Object __ -> throw new AssertionError(); > }; > } > > > Obviously i can tweak the code generator to generate > > static Object result(Object o) { > throw new AssertionError(); > } > > but not be able to compile the former code strike me as odd. > > An expression switch is a poly-expression, so the result type is back-propagated from the return type of the method result, so it should be Object. > > Moreover, if the switch is not a switch expression but a switch statement, the code is also valid > > static Object result(Object o) { > switch (o) { > case Object __ -> throw new AssertionError(); > } > } > > Not be able to compile a switch expression when there is no explicit result type but only an implicit type seems arbitrary to me > (this change is backward compatible because it only makes more codes compiling). > > R?mi From brian.goetz at oracle.com Mon Aug 30 16:08:31 2021 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 30 Aug 2021 12:08:31 -0400 Subject: Revisiting the rule for merging type patterns ? In-Reply-To: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> References: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> Message-ID: <32541adc-09b2-2c66-8113-0d725f6e851b@oracle.com> The thing to recognize here is that the restriction against merging (and fallthrough) is not about _cases_, but about _bindings_, because a binding would have an impossible type.? Right now, there's no way to have one without the other, so its easy to conflate them. As you say, once there's a way to say "there's no binding", it becomes possible to merge otherwise incompatible patterns. So yes, I agree once we revisit underscore (or other means of no-binding patterns), we should refine this. > We use comma in between constants, we should be able to use comma in > between patterns. This was always the intent.? Recall that we discussed cases like: ??? case IntBox(int x), IntBag(int x): and backed away not because they were unsound, but because they presented confusing questions like "where is the declaration of x". On 8/28/2021 5:42 PM, Remi Forax wrote: > I believe that the rule for merging type pattern is overly restrictive, > here is an example of a method that collects all the declared variables (the language is a kind of functional JavaScript i'm using for teaching) > > private static void visitVariable(Expr expr, JSObject env) { > switch (expr) { > case Block block -> { > for (Expr instr : block.instrs()) { > visitVariable(instr, env); > } > } > case Literal literal -> { > // do nothing > } > case FunCall funCall -> { > // do nothing > } > case LocalVarAssignment localVarAssignment -> { > if (localVarAssignment.declaration()) { > env.register(localVarAssignment.name(), env.length()); > } > } > case LocalVarAccess localVarAccess -> { > // do nothing > } > case Fun fun -> { > // do nothing > } > case Return _return -> { > // do nothing > } > case If _if -> { > visitVariable(_if.trueBlock(), env); > visitVariable(_if.falseBlock(), env); > } > case New _new -> { > // do nothing > } > case FieldAccess fieldAccess -> { > // do nothing > } > case FieldAssignment fieldAssignment -> { > // do nothing > } > case MethodCall methodCall -> { > // do nothing > } > default -> throw new AssertionError("unknown case " + expr.getClass()); > }; > } > > Here i can not group the cases that do nothing together because we have explicitly disallow it, > so the code below does not compile > case Literal literal, FunCall funcall -> { > // do nothing > } > > I think we should revisit that discussion and just not introduce the any bindings in that case so the example above will compile but "literal" or "funcall" are not added as local variable. > > Once we will introduce '_', the "correct" way to write such code will be > case Literal _, FunCall _ -> { > // do nothing > } > > regards, > R?mi From john.r.rose at oracle.com Tue Aug 31 00:21:31 2021 From: john.r.rose at oracle.com (John Rose) Date: Tue, 31 Aug 2021 00:21:31 +0000 Subject: Revisiting the rule for merging type patterns ? In-Reply-To: <32541adc-09b2-2c66-8113-0d725f6e851b@oracle.com> References: <693613232.961070.1630186958483.JavaMail.zimbra@u-pem.fr> <32541adc-09b2-2c66-8113-0d725f6e851b@oracle.com> Message-ID: On Aug 30, 2021, at 9:08 AM, Brian Goetz > wrote: This was always the intent. Recall that we discussed cases like: case IntBox(int x), IntBag(int x): and backed away not because they were unsound, but because they presented confusing questions like "where is the declaration of x?. I think it is reasonable to make a sort of ?dead zone? for x after the OR-pattern (which is introduced by the comma if you squint right). By that I mean, ?x? is not definitely assigned after the OR-pattern, which is after the ?:?. That would allow the following guard expression to use ?x? in a place where it has only one candidate binding: case IntBox(int x) && isBoxable(x), IntBag(int x): Then there is the question of whether it would be possible to design rules that would allow this: case IntBox(int x) && isBoxable(x), IntBag(int x) && isBaggable(x): (?Keeping the two bindings of x distinct, and still disallowing x after the colon.) But in the end, such fine distinctions do not add much value, given that alpha-renaming fixes everything: case IntBox(int x) && isBoxable(x), IntBag(int x2) && isBaggable(x2): Which leaves me with just one question: Do the rules allow that last example, or is there a problem with OR-patterns that carry bindings? After all, it would seem that OR-patterns with bindings are never useful, but that ?would seem? is wrong, because guards close to the OR-pattern term are useful. ? John