From newblood17 at gmail.com Tue Oct 1 13:09:43 2024 From: newblood17 at gmail.com (mirage) Date: Tue, 1 Oct 2024 08:09:43 -0500 Subject: switch statements with empty parameters parameters Message-ID: Hello. In the recent years switch has been enhanced and there are some discussions about enhancing it even further with try - catch evaluation style inside the switch itself. i was wondering if an additional enhancement could be to be able to use an empty parameter switch so we can use switch as a general-purpose replacement of if-else chains. Switch has many advantages over if-else chains, being these the most relevant. - The code it's cleaner and more readable, even with nested switch expressions. - Switch can be an expression, so it can return an assign a value to a variable. nowadays we can use something like this. var i = someIntMethodParameter; var j = someStringMethodParameter var res = switch (new Object()){ case Object _ when i < 5 -> 5; case Object _ when i > 10 -> 10; case Object _ when j.length() < 10 -> 20; case null -> 0; default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; as we can see here this is effectively a replacement for if-else chains that returns the first true case, but there are some problems with this syntax and semantics . I was wondering if it could be a good idea to * };* -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Oct 1 13:20:29 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 1 Oct 2024 13:20:29 +0000 Subject: switch statements with empty parameters parameters In-Reply-To: References: Message-ID: <6FF69CA7-3839-4DEC-A3B9-E2EBC5B21EEB@oracle.com> Yes, this has been considered several times. It is one of those things that seems clever at first, and it is not intrinsically flawed, but over time seems less attractive, for a number of reasons. To start with, let?s recognize that `switch` doesn?t really need to exist; it doesn?t express anything that we can?t express with `if` and other control flows. So why do we have it? Because it is _more constrained_ than arbitrary if-else-break logic, and therefore we can write simpler programs with it. If we give switch more kinds of jobs to do, we risk giving up that simplicity benefit. The essence of switch is to ask ?is this thing one of these, if so, do the appropriate thing.? It started out very limited (limited in selector types and the kinds of cases), and we generalized it to more types and more powerful cases (through patterns and guards), while at the same time, retaining that essence of ?pick one based on what this target is.? So the answer to your question is: yes, it?s been considered; yes, it?s not totally dumb (many proposed language features don?t meet this bar); but no, it does not seem the best thing we could be working on now. On Oct 1, 2024, at 9:09 AM, mirage > wrote: Hello. In the recent years switch has been enhanced and there are some discussions about enhancing it even further with try - catch evaluation style inside the switch itself. i was wondering if an additional enhancement could be to be able to use an empty parameter switch so we can use switch as a general-purpose replacement of if-else chains. Switch has many advantages over if-else chains, being these the most relevant. - The code it's cleaner and more readable, even with nested switch expressions. - Switch can be an expression, so it can return an assign a value to a variable. nowadays we can use something like this. var i = someIntMethodParameter; var j = someStringMethodParameter var res = switch (new Object()){ case Object _ when i < 5 -> 5; case Object _ when i > 10 -> 10; case Object _ when j.length() < 10 -> 20; case null -> 0; default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; as we can see here this is effectively a replacement for if-else chains that returns the first true case, but there are some problems with this syntax and semantics . I was wondering if it could be a good idea to }; -------------- next part -------------- An HTML attachment was scrubbed... URL: From newblood17 at gmail.com Tue Oct 1 13:16:50 2024 From: newblood17 at gmail.com (mirage) Date: Tue, 1 Oct 2024 08:16:50 -0500 Subject: Switch statements with empty parameters Message-ID: Hello. In the recent years switch has been enhanced and there are some discussions about enhancing it even further with try - catch evaluation style inside the switch itself. i was wondering if an additional enhancement could be to be able to use an empty parameter switch so we can use switch as a general-purpose replacement of if-else chains. Switch has many advantages over if-else chains, being these the most relevant. - The code it's cleaner and more readable, even with nested switch expressions. - Switch can be an expression, so it can return an assign a value to a variable. nowadays we can use something like this. var i = someIntMethodParameter; var j = someStringMethodParameter var res = switch (new Object()){ case Object _ when i < 5 -> 5; case Object _ when i > 10 -> 10; case Object _ when j.length() < 10 -> 20; case null -> 0; default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; as we can see here this is effectively a replacement for if-else chains that returns the first true case, but there are some problems with this syntax and semantics. - we have to declare an object (or whatever other parameter) in the switch even if we are not using it. - we have to use some pattern matching syntax, even if we are not using it. . I was wondering if it could be a good idea to allow empty parameters switch. i could look something like this. var res = switch (){ case when i < 5 -> 5; case when i > 10 -> 10; case when j.length() < 10 -> 20; default -> -1; }; This way we could replace long if-else chains of validations with a better alternative, turning switch into a general-purpose control construct -------------- next part -------------- An HTML attachment was scrubbed... URL: From rotanolexandr842 at gmail.com Tue Oct 1 13:39:16 2024 From: rotanolexandr842 at gmail.com (Olexandr Rotan) Date: Tue, 1 Oct 2024 16:39:16 +0300 Subject: switch statements with empty parameters parameters In-Reply-To: <6FF69CA7-3839-4DEC-A3B9-E2EBC5B21EEB@oracle.com> References: <6FF69CA7-3839-4DEC-A3B9-E2EBC5B21EEB@oracle.com> Message-ID: I would say that the moment there is something except i in switch you are violating SRP on statement level. If I were to advocate for alike feature, I would much rather support something like var res = switch (i) { case < 5 -> 5; case > 10 -> 10; case null -> 0 default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; (something like this is present in .NET). Adding case ... j.length() < 10 -> 20; seems like it steps outside of switch scope, which is pattern matching on switch argument, to me. Regrads On Tue, Oct 1, 2024 at 4:20?PM Brian Goetz wrote: > Yes, this has been considered several times. It is one of those things > that seems clever at first, and it is not intrinsically flawed, but over > time seems less attractive, for a number of reasons. > > To start with, let?s recognize that `switch` doesn?t really need to exist; > it doesn?t express anything that we can?t express with `if` and other > control flows. So why do we have it? Because it is _more constrained_ > than arbitrary if-else-break logic, and therefore we can write simpler > programs with it. If we give switch more kinds of jobs to do, we risk > giving up that simplicity benefit. > > The essence of switch is to ask ?is this thing one of these, if so, do the > appropriate thing.? It started out very limited (limited in selector types > and the kinds of cases), and we generalized it to more types and more > powerful cases (through patterns and guards), while at the same time, > retaining that essence of ?pick one based on what this target is.? > > So the answer to your question is: yes, it?s been considered; yes, it?s > not totally dumb (many proposed language features don?t meet this bar); but > no, it does not seem the best thing we could be working on now. > > > On Oct 1, 2024, at 9:09 AM, mirage wrote: > > Hello. > > In the recent years switch has been enhanced and there are some > discussions about enhancing it even further with try - catch evaluation > style inside the switch itself. > > i was wondering if an additional enhancement could be to be able to use an > empty parameter switch so we can use switch as a general-purpose > replacement of if-else chains. Switch has many advantages over if-else > chains, being these the most relevant. > > - The code it's cleaner and more readable, even with nested switch > expressions. > - Switch can be an expression, so it can return an assign a value to a > variable. > > nowadays we can use something like this. > > var i = someIntMethodParameter; > var j = someStringMethodParameter > var res = switch (new Object()){ > case Object _ when i < 5 -> 5; > case Object _ when i > 10 -> 10; > case Object _ when j.length() < 10 -> 20; > case null -> 0; > default -> throw new IllegalStateException("Unexpected value: " + new > Object()); > }; > > as we can see here this is effectively a replacement for if-else chains > that returns the first true case, but there are some problems with this > syntax and semantics > > . I was wondering if it could be a good idea to > > * > };* > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Oct 1 13:45:05 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 1 Oct 2024 13:45:05 +0000 Subject: switch statements with empty parameters parameters In-Reply-To: References: <6FF69CA7-3839-4DEC-A3B9-E2EBC5B21EEB@oracle.com> Message-ID: <6EBC8293-D3FA-4254-B8A8-7C883748349E@oracle.com> For those following along: Olexandr is appealing to a feature of C# where `< n` is a pattern which is applicable to numeric types, and matches when the inequality holds. If we had such patterns, switch wouldn?t need to change. (Such patterns are not currently on the roadmap, for a number of reasons but mostly because there are so many higher-value features ahead of it in the queue.). On Oct 1, 2024, at 9:39 AM, Olexandr Rotan > wrote: I would say that the moment there is something except i in switch you are violating SRP on statement level. If I were to advocate for alike feature, I would much rather support something like var res = switch (i) { case < 5 -> 5; case > 10 -> 10; case null -> 0 default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; (something like this is present in .NET). Adding case ... j.length() < 10 -> 20; seems like it steps outside of switch scope, which is pattern matching on switch argument, to me. Regrads On Tue, Oct 1, 2024 at 4:20?PM Brian Goetz > wrote: Yes, this has been considered several times. It is one of those things that seems clever at first, and it is not intrinsically flawed, but over time seems less attractive, for a number of reasons. To start with, let?s recognize that `switch` doesn?t really need to exist; it doesn?t express anything that we can?t express with `if` and other control flows. So why do we have it? Because it is _more constrained_ than arbitrary if-else-break logic, and therefore we can write simpler programs with it. If we give switch more kinds of jobs to do, we risk giving up that simplicity benefit. The essence of switch is to ask ?is this thing one of these, if so, do the appropriate thing.? It started out very limited (limited in selector types and the kinds of cases), and we generalized it to more types and more powerful cases (through patterns and guards), while at the same time, retaining that essence of ?pick one based on what this target is.? So the answer to your question is: yes, it?s been considered; yes, it?s not totally dumb (many proposed language features don?t meet this bar); but no, it does not seem the best thing we could be working on now. On Oct 1, 2024, at 9:09 AM, mirage > wrote: Hello. In the recent years switch has been enhanced and there are some discussions about enhancing it even further with try - catch evaluation style inside the switch itself. i was wondering if an additional enhancement could be to be able to use an empty parameter switch so we can use switch as a general-purpose replacement of if-else chains. Switch has many advantages over if-else chains, being these the most relevant. - The code it's cleaner and more readable, even with nested switch expressions. - Switch can be an expression, so it can return an assign a value to a variable. nowadays we can use something like this. var i = someIntMethodParameter; var j = someStringMethodParameter var res = switch (new Object()){ case Object _ when i < 5 -> 5; case Object _ when i > 10 -> 10; case Object _ when j.length() < 10 -> 20; case null -> 0; default -> throw new IllegalStateException("Unexpected value: " + new Object()); }; as we can see here this is effectively a replacement for if-else chains that returns the first true case, but there are some problems with this syntax and semantics . I was wondering if it could be a good idea to }; -------------- next part -------------- An HTML attachment was scrubbed... URL: From holo3146 at gmail.com Tue Oct 1 14:13:55 2024 From: holo3146 at gmail.com (Holo The Sage Wolf) Date: Tue, 1 Oct 2024 17:13:55 +0300 Subject: switch statements with empty parameters parameters In-Reply-To: <6EBC8293-D3FA-4254-B8A8-7C883748349E@oracle.com> References: <6FF69CA7-3839-4DEC-A3B9-E2EBC5B21EEB@oracle.com> <6EBC8293-D3FA-4254-B8A8-7C883748349E@oracle.com> Message-ID: While the suggestion does violate SRP, it is not without reason. Java currently doesn't have unrestricted conditional expression, switch without parameter will solve this without much language complexity. Kotlin has this in their `when` expression. The feature you are suggesting is completely different and I don't think the 2 features should be talked about in the same thread. On Tue, 1 Oct 2024, 16:45 Brian Goetz, wrote: > For those following along: Olexandr is appealing to a feature of C# where > `< n` is a pattern which is applicable to numeric types, and matches when > the inequality holds. If we had such patterns, switch wouldn?t need to > change. (Such patterns are not currently on the roadmap, for a number of > reasons but mostly because there are so many higher-value features ahead of > it in the queue.). > > On Oct 1, 2024, at 9:39 AM, Olexandr Rotan > wrote: > > I would say that the moment there is something except i in switch you are > violating SRP on statement level. If I were to advocate for alike feature, > I would much rather support something like > > var res = switch (i) { > case < 5 -> 5; > case > 10 -> 10; > case null -> 0 > default -> throw new IllegalStateException("Unexpected value: " + new > Object()); > }; > > (something like this is present in .NET). Adding case ... j.length() < 10 > -> 20; seems like it steps outside of switch scope, which is pattern > matching on switch argument, to me. > > Regrads > > On Tue, Oct 1, 2024 at 4:20?PM Brian Goetz wrote: > >> Yes, this has been considered several times. It is one of those things >> that seems clever at first, and it is not intrinsically flawed, but over >> time seems less attractive, for a number of reasons. >> >> To start with, let?s recognize that `switch` doesn?t really need to >> exist; it doesn?t express anything that we can?t express with `if` and >> other control flows. So why do we have it? Because it is _more >> constrained_ than arbitrary if-else-break logic, and therefore we can write >> simpler programs with it. If we give switch more kinds of jobs to do, we >> risk giving up that simplicity benefit. >> >> The essence of switch is to ask ?is this thing one of these, if so, do >> the appropriate thing.? It started out very limited (limited in selector >> types and the kinds of cases), and we generalized it to more types and more >> powerful cases (through patterns and guards), while at the same time, >> retaining that essence of ?pick one based on what this target is.? >> >> So the answer to your question is: yes, it?s been considered; yes, it?s >> not totally dumb (many proposed language features don?t meet this bar); but >> no, it does not seem the best thing we could be working on now. >> >> >> On Oct 1, 2024, at 9:09 AM, mirage wrote: >> >> Hello. >> >> In the recent years switch has been enhanced and there are some >> discussions about enhancing it even further with try - catch evaluation >> style inside the switch itself. >> >> i was wondering if an additional enhancement could be to be able to use >> an empty parameter switch so we can use switch as a general-purpose >> replacement of if-else chains. Switch has many advantages over if-else >> chains, being these the most relevant. >> >> - The code it's cleaner and more readable, even with nested switch >> expressions. >> - Switch can be an expression, so it can return an assign a value to a >> variable. >> >> nowadays we can use something like this. >> >> var i = someIntMethodParameter; >> var j = someStringMethodParameter >> var res = switch (new Object()){ >> case Object _ when i < 5 -> 5; >> case Object _ when i > 10 -> 10; >> case Object _ when j.length() < 10 -> 20; >> case null -> 0; >> default -> throw new IllegalStateException("Unexpected value: " + new >> Object()); >> }; >> >> as we can see here this is effectively a replacement for if-else chains >> that returns the first true case, but there are some problems with this >> syntax and semantics >> >> . I was wondering if it could be a good idea to >> >> * >> };* >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Wed Oct 2 13:14:32 2024 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Wed, 2 Oct 2024 13:14:32 +0000 Subject: New candidate JEP: 492: Flexible Constructor Bodies (Third Preview) Message-ID: <20241002131430.EBCC577CE34@eggemoggin.niobe.net> https://openjdk.org/jeps/492 Summary: In constructors in the Java programming language, allow statements to appear before an explicit constructor invocation, i.e., super(..) or this(..). The statements cannot reference the instance under construction, but they can initialize its fields. Initializing fields before invoking another constructor makes a class more reliable when methods are overridden. This is a preview language feature. - Mark From archie.cobbs at gmail.com Wed Oct 2 21:33:16 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 2 Oct 2024 16:33:16 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: Message-ID: After some reflection on this, I'd like to propose the following. To recap, the problem being addressed is that for() code like this doesn't compile: for (int i = 0; i < 10; i++) { Runnable r = () -> System.out.println(i); // error: "i" is not effectively final } There are two separate ideas proposed in JDK-8300691: 1. Allow for() loop iteration variables to be declared final but still be mutated in the step 2. Make for() loop iterations variables be effectively final at the start of the body Both ideas would both solve the stated problem. Idea #1 would include an additional benefit, which is that knowing the variable is final in the body of the loop aids the developer when reasoning about that code. However, idea #1 also has some subtle issues (see JDK-8300691 for details) and is somewhat awkward in creating a "final" variable that can still be reassigned. Idea #2 is straightforward and seems to be intuitively agreeable. It solves the original problem with minimal fuss. The added benefit of Idea #1 doesn't seem worth the extra mental complexity. Therefore, I think we should stick with idea #2 for now, i.e., just make for() loop iterations variables be effectively final at the start of the body. Thoughts? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Thu Oct 10 07:58:22 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 10 Oct 2024 09:58:22 +0200 (CEST) Subject: Yield _ is not recognized as a valid code by javac Message-ID: <997636887.32119584.1728547102317.JavaMail.zimbra@univ-eiffel.fr> Hello, It seems javac grammar does not allow yield to be follow by an '_'. void main(String[] args) { Consumer value = switch (args[0]) { case "foo" -> { yield _ -> {}; } default -> throw new AssertionError(); }; } Both ecj and the front compiler of IntelliJ as no trouble with this code, it seems to be just a javac bug. regards, R?mi From nlisker at gmail.com Thu Oct 10 08:04:00 2024 From: nlisker at gmail.com (Nir Lisker) Date: Thu, 10 Oct 2024 11:04:00 +0300 Subject: More comprehensive type inference for pattern matching Message-ID: Hi, Give a simple generic wrapper, class Container { T item; } pattern matching can find out what T is for 'item', but not for its container: void switchItem(Container container) { if (container.item instanceof Number num) { acceptNumber(num); acceptNumberContainer(container); // error } } The information is technically there to make the derivation. I can envision some complexities with bound constraints, but seeing as I can't check 'instanceof Container`, can the compiler not be smarter? - Nir -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Thu Oct 10 08:06:33 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 10 Oct 2024 10:06:33 +0200 (CEST) Subject: Yield _ is not recognized as a valid code by javac In-Reply-To: <997636887.32119584.1728547102317.JavaMail.zimbra@univ-eiffel.fr> References: <997636887.32119584.1728547102317.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <1727432801.32125416.1728547593101.JavaMail.zimbra@univ-eiffel.fr> Opps, i click submit too fast, an issue was open (https://bugs.openjdk.org/browse/JDK-8335136) but it has been closed without me understanding why. R?mi ----- Original Message ----- > From: "Remi Forax" > To: "amber-dev" > Sent: Thursday, October 10, 2024 9:58:22 AM > Subject: Yield _ is not recognized as a valid code by javac > Hello, > It seems javac grammar does not allow yield to be follow by an '_'. > > void main(String[] args) { > Consumer value = switch (args[0]) { > case "foo" -> { > yield _ -> {}; > } > default -> throw new AssertionError(); > }; > } > > Both ecj and the front compiler of IntelliJ as no trouble with this code, > it seems to be just a javac bug. > > regards, > R?mi From forax at univ-mlv.fr Thu Oct 10 08:38:09 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 10 Oct 2024 10:38:09 +0200 (CEST) Subject: Yield _ is not recognized as a valid code by javac In-Reply-To: <1727432801.32125416.1728547593101.JavaMail.zimbra@univ-eiffel.fr> References: <997636887.32119584.1728547102317.JavaMail.zimbra@univ-eiffel.fr> <1727432801.32125416.1728547593101.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <1761154481.32160828.1728549489825.JavaMail.zimbra@univ-eiffel.fr> Ok, i'm at Devoxx BE seated near Stuart Marks and he explained to me that it was integrated in Java 24, it's me not being able to decipher the bug report correctly, so sorry for the noise. R?mi ----- Original Message ----- > From: "Remi Forax" > To: "amber-dev" > Sent: Thursday, October 10, 2024 10:06:33 AM > Subject: Re: Yield _ is not recognized as a valid code by javac > Opps, i click submit too fast, an issue was open > (https://bugs.openjdk.org/browse/JDK-8335136) > but it has been closed without me understanding why. > > R?mi > > ----- Original Message ----- >> From: "Remi Forax" >> To: "amber-dev" >> Sent: Thursday, October 10, 2024 9:58:22 AM >> Subject: Yield _ is not recognized as a valid code by javac > >> Hello, >> It seems javac grammar does not allow yield to be follow by an '_'. >> >> void main(String[] args) { >> Consumer value = switch (args[0]) { >> case "foo" -> { >> yield _ -> {}; >> } >> default -> throw new AssertionError(); >> }; >> } >> >> Both ecj and the front compiler of IntelliJ as no trouble with this code, >> it seems to be just a javac bug. >> >> regards, > > R?mi From amaembo at gmail.com Thu Oct 10 10:24:17 2024 From: amaembo at gmail.com (Tagir Valeev) Date: Thu, 10 Oct 2024 12:24:17 +0200 Subject: More comprehensive type inference for pattern matching In-Reply-To: References: Message-ID: Hello! This would basically bring flow-typing to Java (variable type may be narrowed at use site, depending on the context; known as smart-casts in Kotlin). I think, this is something Java tries to avoid. That's why a instanceof B b introduces a new variable, rather than changes the type of a. Another problem is that container.item instanceof Number does not imply container instanceof Container. It could easily be Container. Imagine class Container { T item, item2; } If you checked that item is Number, it doesn't mean that item2 is also Number. It could be Container having Integer and String in the fields. If you pass it to a place which accepts Container and reads item2, you'll get a problem. It's also possible that it's Container, not Container. Again, if you pass it to the place where Container is accepted, it can rewrite your Integer field with Double, and later the code that still assumes it's Container will blow up. With best regards, Tagir Valeev On Thu, Oct 10, 2024, 11:17 Nir Lisker wrote: > Hi, > > Give a simple generic wrapper, > > class Container { > T item; > } > > pattern matching can find out what T is for 'item', but not for its > container: > > void switchItem(Container container) { > if (container.item instanceof Number num) { > acceptNumber(num); > acceptNumberContainer(container); // error > } > } > > The information is technically there to make the derivation. I can > envision some complexities with bound constraints, but seeing as I can't > check 'instanceof Container`, can the compiler not be smarter? > > - Nir > -------------- next part -------------- An HTML attachment was scrubbed... URL: From nlisker at gmail.com Thu Oct 10 17:29:32 2024 From: nlisker at gmail.com (Nir Lisker) Date: Thu, 10 Oct 2024 20:29:32 +0300 Subject: More comprehensive type inference for pattern matching In-Reply-To: References: Message-ID: Hi Tagir, class Container { > T item1, item2; > } Yes, once you add more items it gets to the "bound constraints" I mentioned. You will need to compute the "lowest common denominator" for the items. If you check the type of item1 there is mathematically not enough information to derive the container type - the user can't know that either, even when solving with pen and paper, so of course you run into problems. However (and please ignore syntax), if (item1 instaceof Integer i && item2 instanceof Long l) { // I know it's Container } if (item1 instaceof Integer i && item2 instanceof String s) { // I know it's Container } It's also possible that it's Container, not Container > Isn't it Container? In any case, at least I know *some* limitation on the container type. As for flow-typing, I don't want to get into the syntax level of needing to bind to a new variable or not, so I'll zoom out a bit. Given any generic class, we can't access any information about its type parameter(s) because of erasure, but this is for run-time. For compile-time, the compiler does many checks for us (otherwise there's no point for generics at all), but it doesn't use all the information available. What users tend to find frustrating is that they can derive a conclusion about the code, but the compiler doesn't do it, so they need to specify it explicitly in frustration. Nullness analysis is an example ("I know this can't be null, so why do I need to tell you that?"), and so is pattern matching for instanceof ("I know this is an X, so why do I need to tell you that?"). What I can say is: "there is enough type information to figure out the type parameter, but it does not do so, so I need to do it explicitly". Doing instanceof against a type parameter (instanceof T) is impossible without (partial?) reification, but there are still many valid cases for wanting to get type info, like switching on Box, Box and Box. This can be *effectively* available by looking at the content, I can solve the constraints on a piece of paper. Local type inference (var) does something similar with the known example. So, I'm not asking for a specific named feature or change like some "reification", "flow-typing", or "pattern matching", I'm asking to alleviate the developer from telling the compiler something it can know. On Thu, Oct 10, 2024 at 1:24?PM Tagir Valeev wrote: > Hello! > > This would basically bring flow-typing to Java (variable type may be > narrowed at use site, depending on the context; known as smart-casts in > Kotlin). I think, this is something Java tries to avoid. That's why a > instanceof B b introduces a new variable, rather than changes the type of a. > > Another problem is that container.item instanceof Number does not imply > container instanceof Container. It could easily be > Container. Imagine > > class Container { > T item, item2; > } > > If you checked that item is Number, it doesn't mean that item2 is also > Number. It could be Container having Integer and String in the > fields. If you pass it to a place which accepts Container and reads > item2, you'll get a problem. > > It's also possible that it's Container, not Container. > Again, if you pass it to the place where Container is accepted, it > can rewrite your Integer field with Double, and later the code that still > assumes it's Container will blow up. > > With best regards, > Tagir Valeev > > > On Thu, Oct 10, 2024, 11:17 Nir Lisker wrote: > >> Hi, >> >> Give a simple generic wrapper, >> >> class Container { >> T item; >> } >> >> pattern matching can find out what T is for 'item', but not for its >> container: >> >> void switchItem(Container container) { >> if (container.item instanceof Number num) { >> acceptNumber(num); >> acceptNumberContainer(container); // error >> } >> } >> >> The information is technically there to make the derivation. I can >> envision some complexities with bound constraints, but seeing as I can't >> check 'instanceof Container`, can the compiler not be smarter? >> >> - Nir >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Sat Oct 12 21:11:08 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 12 Oct 2024 23:11:08 +0200 (CEST) Subject: javac can not infer a var inside a record pattern correctly Message-ID: <1577652712.36000977.1728767468724.JavaMail.zimbra@univ-eiffel.fr> Hello, this code does not compile correctly: public class StaticSelect { record A(T value) {} record Pair(A a, int size) {} static Pair bar(A a) { return new Pair<>(a, 0); } void foo(A a) { switch (bar(a)) { case Pair(/*A*/ var a2, int s) -> {} } } } Fails with javac either JDK 23 or JDK 24 build 19 javac StaticSelect.java error: cannot select a static class from a parameterized type 1 error No idea why, but changing "var a2" by "A a2" fixes the issue. regards, R?mi From jan.lahoda at oracle.com Mon Oct 14 05:37:20 2024 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Mon, 14 Oct 2024 07:37:20 +0200 Subject: [External] : javac can not infer a var inside a record pattern correctly In-Reply-To: <1577652712.36000977.1728767468724.JavaMail.zimbra@univ-eiffel.fr> References: <1577652712.36000977.1728767468724.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <028a9b48-80c1-47ae-bfa8-72dace338f0d@oracle.com> Hi Remi, Thanks for the report. I believe this is already reported as: https://bugs.openjdk.org/browse/JDK-8341901 which is under progress. Thanks, ??? Jan On 12. 10. 24 23:11, Remi Forax wrote: > Hello, > this code does not compile correctly: > > public class StaticSelect { > record A(T value) {} > record Pair(A a, int size) {} > > static Pair bar(A a) { > return new Pair<>(a, 0); > } > > void foo(A a) { > switch (bar(a)) { > case Pair(/*A*/ var a2, int s) -> {} > } > } > } > > > Fails with javac either JDK 23 or JDK 24 build 19 > > javac StaticSelect.java > error: cannot select a static class from a parameterized type > 1 error > > No idea why, but changing "var a2" by "A a2" fixes the issue. > > regards, > R?mi From maurizio.cimadamore at oracle.com Wed Oct 16 13:56:19 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 16 Oct 2024 14:56:19 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: Message-ID: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Hi Archie, there were several interesting design discussions on the JEP [1] you have created for this. An intersting angle we discussed was whether we feel imperative for loops are special enough to deserve special treatment, or whether this is the start of a loosening process that will eventually lead to allow capture for every local variable /value/. In order to better characterize the nature of the problem we?re dealing with, it would be great if we could gather some more evidence on how many ?dummy? local variables are introduced for the sole purpose of being able to capture them in a lambda/inner class. More precisely, a ?dummy? local variable is a local variable that: * is initialized with the value of some other local variable o is only referenced inside a capture context (either lambda or inner class) (corollary: all ?dummy? local variables are effectively-final). Example: |int x = ... ... x = ... // reassignment ... int x2 = x; // x2 is effectively-final ... () -> x2; // x2 is only used here! | Could you come up with a javac patch that detects such ?dummy? variable declarations and prints a note/warning in the compiler output? Then we can try to run the modified javac to build the JDK and see how many warnings are found there. Similarly, we can try the modified compiler against Maven artifacts (we have some infrastructure to do that), or against other interesting codebases (perhaps Liam, cc?ed, might help here?) Let me know what you think. Cheers Maurizio [1] - https://git.openjdk.org/jdk/pull/21415 On 11/09/2024 00:23, Archie Cobbs wrote: > I'm curious about this possible future language tweak and have been > looking at it more closely: https://bugs.openjdk.org/browse/JDK-8300691 > > I think this would be a nice practical change that fits well within > the Amber ambit. However, I'm stuck on one question. > > To summarize, there are two independent changes being proposed: > > 1. Prevent statements in for() loop steps from causing for() loop > variables to lose their "effectively final" status > 2. Allow final for() loop variables to be mutated in the for() step > (but not the for() body) > > Change #1 would allow code like this: > > for (int i = 0; i < 10; i++) { > ??? Runnable r = () -> System.out.println(i);?? // hooray, "i" is > effectively final > } > > Change #2 would allow code like this: > > for (final int i = 0; i < 10; i++) { > System.out.println(i);????????? // we can rest assured "i" can't > change in here > } > > Change #1 is straightforward but Change #2 raises an issue. A final > initialized variable is not only immutable but also can be a constant > expression, and this affects reachability analysis. > > For example, these two examples do not compile: > > final int x = 0; > while (x != 0) > System.out.println(x);???????? // error: unreachable statement > System.out.println("done"); > > final int x = 0; > while (x == 0) > System.out.println(x); > System.out.println("done"); // error: unreachable statement > > We shouldn't expect the equivalent for() statements to compile either, > and in fact today they don't: > > for (final int x = 0; x != 0; ) > ? ? System.out.println(x); ??????? // error: unreachable statement > System.out.println("done"); > > for (final int x = 0; x == 0; ) > ??? System.out.println(x); > System.out.println("done");??????? // error: unreachable statement > > But now suppose we add a step, which Change #2 would newly allow: > > for (final int x = 0; x != 0; x++) > ? ? System.out.println(x); ??????? // error: unreachable statement... ? > System.out.println("done"); > > for (final int x = 0; x == 0; x++) > ??? System.out.println(x); > System.out.println("done");??????? // NOT an unreachable statement > > In the first example, the inner statement is still unreachable, so > it's OK for the compiler to still report that error, but in the second > example, the final statement is now obviously reachable, so the > compiler must? do something different. Moreover it would be doing > something different based on inspection of the step for mutations to > "x", which seems like "spooky action at a distance" and could be > spec-challenging. > > Alternatively, the compiler could change its behavior to never > consider final loop variables as constant expressions, but this could > break existing code. > > Of course, if Change #2 had too many issues, Change #1 would still be > useful on its own. > > Thoughts? > > Thanks, > -Archie > > -- > Archie L. Cobbs ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Oct 16 14:11:34 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 09:11:34 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: Hi Maurizio, On Wed, Oct 16, 2024 at 8:56?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Could you come up with a javac patch that detects such ?dummy? variable > declarations and prints a note/warning in the compiler output? > Excellent idea - I agree this is something worth further exploration to better understand. I will work on it and report back. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Wed Oct 16 16:03:15 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 16 Oct 2024 17:03:15 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: <8396d02d-7a7e-42c1-aa22-c3a0f2f07998@oracle.com> Thanks! Maurizio On 16/10/2024 15:11, Archie Cobbs wrote: > Hi Maurizio, > > On Wed, Oct 16, 2024 at 8:56?AM Maurizio Cimadamore > wrote: > > Could you come up with a javac patch that detects such ?dummy? > variable declarations and prints a note/warning in the compiler > output? > > Excellent idea - I agree this is something worth further exploration > to better understand. > > I will work on it and report back. > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Oct 16 20:44:40 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 15:44:40 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: Hi Maurizio, Please see https://github.com/openjdk/jdk/compare/master...archiecobbs:jdk:dummy-variable-detector?expand=1 I made it a note instead of a warning so that builds would not be artificially halted. Here's an example: $ cat Test.java class Test { { for (int i = 1; i <= 3; i++) { int i2 = i; Runnable r = () -> System.out.println(i2); } } } $ javac Test.java flex-test/Test.java:4: Note: detected effectively final "dummy variable" i2 int i2 = i; ^ I *think* the logic is accurate but it could probably use a quick review. -Archie On Wed, Oct 16, 2024 at 9:11?AM Archie Cobbs wrote: > Hi Maurizio, > > On Wed, Oct 16, 2024 at 8:56?AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> Could you come up with a javac patch that detects such ?dummy? variable >> declarations and prints a note/warning in the compiler output? >> > Excellent idea - I agree this is something worth further exploration to > better understand. > > I will work on it and report back. > > -Archie > > -- > Archie L. Cobbs > -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Wed Oct 16 20:56:09 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 16 Oct 2024 21:56:09 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> Hi Archie, looks very good. Only one comment. Here: |// Check for a possible "dummy variable" declaration if (tree.sym.pos >= startPos && (tree.sym.owner.kind == MTH || tree.sym.owner.kind == VAR) && tree.init instanceof JCIdent) dummyVariables.put(tree.sym, new DummyVariable(tree.pos(), tree.sym)); | I think we have to check whether the symbol under tree.init is that of a local variable. E.g. we don?t want the finder to pick up stuff like: |String a = b | Where |b| is a field in the current class. Maurizio On 16/10/2024 21:44, Archie Cobbs wrote: > Hi Maurizio, > > Please see > https://github.com/openjdk/jdk/compare/master...archiecobbs:jdk:dummy-variable-detector?expand=1 > > > I made it a note instead of a warning so that builds would not be > artificially halted. > > Here's an example: > > $ cat Test.java > class Test { > ? ? { > ? ? ? ? for (int i = 1; i <= 3; i++) { > ? ? ? ? ? ? int i2 = i; > ? ? ? ? ? ? Runnable r = () -> System.out.println(i2); > ? ? ? ? } > ? ? } > } > $ javac Test.java > flex-test/Test.java:4: Note: detected effectively final "dummy > variable" i2 > ? ? ? ? ? ? int i2 = i; > ? ? ? ? ? ? ? ? ^ > I *think* the logic is accurate but it could probably use a quick review. > > -Archie > > On Wed, Oct 16, 2024 at 9:11?AM Archie Cobbs > wrote: > > Hi Maurizio, > > On Wed, Oct 16, 2024 at 8:56?AM Maurizio Cimadamore > wrote: > > Could you come up with a javac patch that detects such ?dummy? > variable declarations and prints a note/warning in the > compiler output? > > Excellent idea - I agree this is something worth further > exploration to better understand. > > I will work on it and report back. > > -Archie > > -- > Archie L. Cobbs > > > > -- > Archie L. Cobbs ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Oct 16 21:03:41 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 16:03:41 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> Message-ID: On Wed, Oct 16, 2024 at 3:56?PM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > think we have to check whether the symbol under tree.init is that of a > local variable. > Oops, thanks. Should be fixed now. FWIW when I build the JDK itself with this change it outputs 113 notes. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Wed Oct 16 21:37:25 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 16 Oct 2024 22:37:25 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> Message-ID: Ok, now onto an improvements that might help us classify the results more easily. Remember, our ultimate goal would be to see in which context these variables are introduced. E.g. is it a for loop, is it a method declaration, or an else block? I was thinking of doing this in Attr using Env but on second though, that seems to complex. Instead, it would be better if you just created a new visitor in Flow whose only responsibility is that of populating the DummyVariable map you already have. This new visitor might keep track of the innermost "interesting" enclosing context, and when you create the dummy variable, you note that context down. Possible interesting contexts are: * if/then/else * loop bodies (of all kinds) * try/catch blocks * switch * method/constructor body * static/instance initializer * lambda expression I probably forgot a few - but hopefully it's enough to get the message across :-) The note/warning will then include the context in which the dummy variable was found (e.g. something like FOR, WHILE, TRY, CATCH. Just use the name of the tree tag, which is an enum, so should render nicely). Thanks Maurizio On 16/10/2024 22:03, Archie Cobbs wrote: > On Wed, Oct 16, 2024 at 3:56?PM Maurizio Cimadamore > wrote: > > ?think we have to check whether the symbol under tree.init is that > of a local variable. > > Oops, thanks. Should be fixed now. > > FWIW when I build the JDK itself with this change it outputs 113 notes. > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Oct 16 23:11:13 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 18:11:13 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> Message-ID: Hi Maurizio, On Wed, Oct 16, 2024 at 4:37?PM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Instead, it would be better if you just created a new visitor in Flow > whose only responsibility is that of populating the DummyVariable map you > already have. > > This new visitor might keep track of the innermost "interesting" enclosing > context, and when you create the dummy variable, you note that context down. > Nice idea... see 08c8b1f3c64 for a stab at it. I added special logic to include pseudo-tags for STATIC_INITIALIZER and INSTANCE_INITIALIZER. There are surely some trade-offs regarding what types are "interesting", might be worth tweaking. Here are the stats from the JDK: 42 METHODDEF 32 IF 21 TRY 10 FORLOOP 3 DOLOOP 2 WHILELOOP 2 CASE 1 FOREACHLOOP -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Thu Oct 17 00:09:25 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 16 Oct 2024 20:09:25 -0400 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? Message-ID: Hello Amber Dev Team, In Java 23 JLS 15.29, it says that a constant expression can only be made up of primitive LITERALS, String LITERALS, a couple of operations, and CONSTANT VARIABLES. The word LITERAL means that, for strings, I need to put in the full double quotes (or triple double quotes for textblocks) in order to qualify. And the word constant variable is defined in 4.12.4. "A constant variable is a variable of primitive type or type String that is initialized with a constant expression", which is what 15.29 is, mentioned above. Now, to my question -- are there any downsides or obstacles to adding Enum.name() to this list of constant expressions? Enum.name() is a final method, and we know for a fact that, if the class compiles, then it ALWAYS outputs the same value. And therefore, it seems like it aligns nicely with the goals and intents of constant variables. Is there anything bad or wrong about adding enum.name() to the list? I do see some ways that it would provide value, but for now, I just want to get an idea of if it would be bad or wrong to do before seeing if it is worth it at this point in time. Finally, apologies for not having done any preview feature testing lately. I have been juggling personal and work emergencies nonstop. Only recently had a chance to poke my head out from the bomb shelter, and I'm probably going to jump back in shortly. Thank you for your time and help. David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Oct 17 01:33:09 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 20:33:09 -0500 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: On Wed, Oct 16, 2024 at 7:09?PM David Alayachew wrote: > Now, to my question -- are there any downsides or obstacles to adding > Enum.name() to this list of constant expressions? > Just to clarify, this could only work for enum constant literals, e.g., FOOBAR.name() which would obviously have value "foobar". One downside is this could make certain programs no longer compile. These programs may be "oddballs" but still this would represent a backward incompatibility, which is a pretty big no-no in Java-land. To give a concrete example, this program, which now compiles: enum Test { AAA; void meth2() { final String s = AAA.name(); while (s == "AAA") { } System.out.println("done"); } } would start failing to compile like this: Test.java:6: error: unreachable statement System.out.println("done"); ^ An equally relevant question is: what is the upside? Is there a scenario you have in mind where this would lead to an improvement? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Oct 17 01:33:41 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 16 Oct 2024 20:33:41 -0500 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: On Wed, Oct 16, 2024 at 8:33?PM Archie Cobbs wrote: > On Wed, Oct 16, 2024 at 7:09?PM David Alayachew > wrote: > >> Now, to my question -- are there any downsides or obstacles to adding >> Enum.name() to this list of constant expressions? >> > > Just to clarify, this could only work for enum constant literals, e.g., > FOOBAR.name() which would obviously have value "foobar". > Oops, I meant "FOOBAR" ... -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Thu Oct 17 03:32:56 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 16 Oct 2024 23:32:56 -0400 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: Thank you for your response Archie. This was exactly the type of response I was looking for. So, folks leaning on the fact that enum names are not constant might get burned. I agree, these are oddballs. In fact, I would go further and call this a misuse of the API, but if the line is "no breaking backwards compatibility!", then I accept this as a dealbreaker. As for the upsides, my personal use case is that I plan to use this for annotations. There's a couple of benefits, like grouping relevant pieces of information and methods together under the same enum value. Using valueOf(), I can derive a lot of information back from it, allowing me to add a whole bunch of information with a single source of truth. That has been the cause of a lot of bugs for me lately, and the only way to achieve something similar is to do something like nested classes or fake an enum. Why not just use the real thing? On Wed, Oct 16, 2024, 9:33?PM Archie Cobbs wrote: > On Wed, Oct 16, 2024 at 8:33?PM Archie Cobbs > wrote: > >> On Wed, Oct 16, 2024 at 7:09?PM David Alayachew >> wrote: >> >>> Now, to my question -- are there any downsides or obstacles to adding >>> Enum.name() to this list of constant expressions? >>> >> >> Just to clarify, this could only work for enum constant literals, e.g., >> FOOBAR.name() which would obviously have value "foobar". >> > > Oops, I meant "FOOBAR" ... > > -- > Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Oct 17 10:34:38 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 17 Oct 2024 11:34:38 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> Message-ID: <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> This is great info! Thanks. Funny to see the FOREACHLOOP popping out. This code is (at least) from 17 years ago (!!) and predates any form of effectively final analysis - back then even for-each required to hoist the variable in a separate |final| one :-) While looking at the results I realized we have another issue in the analysis. Look at this: https://github.com/openjdk/jdk/blob/master/src/java.xml/share/classes/javax/xml/datatype/FactoryFinder.java#L177 In this case the dummy variable is reported inside the TRY, which is obviously correct. But, I realize, the important info is not where the dummy variable is declared. It's the declaration of the variable it points to in the initializer that matters! In this case, while the dummy variable does appear inside a TRY block, the variable it snapshots is a method parameter, so this should probably say METHODDEF, not TRY. This misclassification might lead to underestimating buckets. For instance, if you have a `for` loop, and inside the for loop you have an `if`, and inside the `if` we declare a dummy variable that captures a variable in the enclosing loop, this will show up as `IF` in the current code. Cheers Maurizio On 17/10/2024 00:11, Archie Cobbs wrote: > Hi Maurizio, > > On Wed, Oct 16, 2024 at 4:37?PM Maurizio Cimadamore > wrote: > > Instead, it would be better if you just created a new visitor in > Flow whose only responsibility is that of populating the > DummyVariable map you already have. > > This new visitor might keep track of the innermost "interesting" > enclosing context, and when you create the dummy variable, you > note that context down. > > Nice idea... see 08c8b1f3c64 > > for a stab at it. > > I added special logic to include pseudo-tags for STATIC_INITIALIZER > and INSTANCE_INITIALIZER. > > There are surely some trade-offs regarding what types are > "interesting", might be worth tweaking. > > Here are the stats from the JDK: > > ? 42 METHODDEF > ? 32 IF > ? 21 TRY > ? 10 FORLOOP > ? ?3 DOLOOP > ? ?2 WHILELOOP > ? ?2 CASE > ? ?1 FOREACHLOOP > > -Archie > > -- > Archie L. Cobbs ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Oct 17 11:58:38 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 Oct 2024 07:58:38 -0400 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: <2e7fbbf5-42f8-4207-b279-83eed5fb943b@oracle.com> Are there any downsides?? OMG yes. The forms of constant expression that the JLS defines are all things that _the language can tell are constants just by looking at them_.? String literals, numeric literals, combinations of the above with operators (e.g., 1+2), and the same laundered through #define-like variables (and even this is starting to skate towards the thin part of the ice.) Whereas Enum.name() is an ordinary Java method.? So defining it as a constant expression is crossing an enormous line, because either (a) the language has to do some analysis to prove that the function body is pure (and even there, you have issues with separate compilation, which I'll ignore for now), or (b) the language has to believe some sort of "trust me bro" annotation that the function is safe to execute at compile time and cache the result without perturbing program semantics, not unlike `constexpr` in C++.?? Both of these are significant language changes. Suppose we thought they were valid (see the exploration in, e.g., my "Below the Fold" JVMLS talk from about 5-6 years ago).? Is this really about Enum::name?? Can you imagine how many thousands of RFEs would follow for "please add String::length to the list too"?? So now, instead of a handful of things that are *obviously constants* (literals) and some things that are one level of indirection away from that (e.g. Math.PI, which as mentioned is already bordering on dodgy), there are going to be thousands of methods that also get this treatment.? Are users supposed to keep this list in their heads?? What happens when something doesn't fold as the user expects it, because some method calls a non-foldable method (or calls it with non-foldable arguments or receiver) seventeen levels down in the call stack? Again, this is doable (again: see my video), but it is no mere "why don't you just" exercise -- it is a major language feature, with an attendant libraries evolution and probably some tooling support too to debug the inevitable "Y U NOT FOLD" problems. But it gets worse that that, because, as I suspected, your real goal was to expand the set of things you can put in annotations. And once you start to expand that, you start to run into the very ad-hoc way that annotations support a fixed number of types. Eventually you are going to ask me to put List.of(... constants ...) in an anno, for all the same arguments, but expanding the set of types here cuts through the classfile format, class loading and validation, language, compiler, and reflection (and likely requires adding new bootstraps as well) in a particularly messy way. On 10/16/2024 8:09 PM, David Alayachew wrote: > Hello Amber Dev Team, > > In Java 23 JLS 15.29, it says that a constant expression can only be > made up of primitive LITERALS, String LITERALS, a couple of > operations, and CONSTANT VARIABLES. > > The word LITERAL means that, for strings, I need to put in the full > double quotes (or triple double quotes for textblocks) in order to > qualify. > > And the word constant variable is defined in 4.12.4. "A constant > variable is a variable of primitive type or type String that is > initialized with a constant expression", which is what 15.29 is, > mentioned above. > > Now, to my question -- are there any downsides or obstacles to adding > Enum.name() to this list of constant expressions? > > Enum.name() is a final method, and we know for a fact that, if the > class compiles, then it ALWAYS outputs the same value. And therefore, > it seems like it aligns nicely with the goals and intents of constant > variables. Is there anything bad or wrong about adding enum.name > () to the list? > > I do see some ways that it would provide value, but for now, I just > want to get an idea of if it would be bad or wrong to do before seeing > if it is worth it at this point in time. > > Finally, apologies for not having done any preview feature testing > lately. I have been juggling personal and work emergencies nonstop. > Only recently had a chance to poke my head out from the bomb shelter, > and I'm probably going to jump back in shortly. > > Thank you for your time and help. > David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Oct 17 14:35:25 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 17 Oct 2024 09:35:25 -0500 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: On Wed, Oct 16, 2024 at 10:33?PM David Alayachew wrote: > As for the upsides, my personal use case is that I plan to use this for > annotations. There's a couple of benefits, like grouping relevant pieces of > information and methods together under the same enum value. Using > valueOf(), I can derive a lot of information back from it, allowing me to > add a whole bunch of information with a single source of truth. That has > been the cause of a lot of bugs for me lately, and the only way to achieve > something similar is to do something like nested classes or fake an enum. > Why not just use the real thing? > Apologies, but I'm not completely understanding what you mean here. Annotations already support enum-valued properties, so what new capability would this change add? While we're on the topic of what you can put in an annotation, I guess I'll throw this idea out there... (previously I was too scared :) Idea: What about allowing lambda values for Class-valued annotation properties when the Class is a functional interface? Example: public @interface GenericStringConstraint { Predicate checker(); Function errorGenerator() default s -> String.format("Invalid value \"%s\"", s); } public class Person { @GenericStringConstraint(checker = s -> !s.isEmpty() && Character.isUpperCase(s.charAt(0))) public String getName() { ... // name must start with uppercase letter } } -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Oct 17 15:03:32 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 17 Oct 2024 10:03:32 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> Message-ID: On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Funny to see the FOREACHLOOP popping out. This code is (at least) from 17 > years ago (!!) and predates any form of effectively final analysis - back > then even for-each required to hoist the variable in a separate final one > :-) > I was wondering about that as well. I didn't realize that there was a point where foreach() already existed and this effectively final tweak was added. I don't see a relevant JEP, did it predate the JEP process? > I realize, the important info is not where the dummy variable is declared. > It's the declaration of the variable it points to in the initializer that > matters! > D'oh, yes of course... easy to fix though. Here are the new stats - these look more like what one might expect: 87 METHODDEF 11 FORLOOP 3 TRY 3 IF 3 FOREACHLOOP 3 DOLOOP 2 WHILELOOP 1 CASE Now there are 3 FOREACHLOOP's :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Oct 17 15:08:41 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 17 Oct 2024 16:08:41 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> Message-ID: On 17/10/2024 16:03, Archie Cobbs wrote: > On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore > wrote: > > Funny to see the FOREACHLOOP popping out. This code is (at least) > from 17 years ago (!!) and predates any form of effectively final > analysis - back then even for-each required to hoist the variable > in a separate |final| one :-) > > > I was wondering about that as well. I didn't realize that there was a > point where foreach() already existed and this effectively final tweak > was added. I don't see a relevant JEP, did it predate the JEP process? Effectively final support was added as part of Java 8 and Project Lambda. Java 7 also had some bits of effective finality here and there, but Java 8 is what sealed the deal. Back then we did not have the JEP process. > > I realize, the important info is not where the dummy variable is > declared. It's the declaration of the variable it points to in the > initializer that matters! > > > D'oh, yes of course... easy to fix though. Thanks > > Here are the new stats - these look more like what one might expect: > > ? 87 METHODDEF > ? 11 FORLOOP > ? ?3 TRY > ? ?3 IF > ? ?3 FOREACHLOOP > ? ?3 DOLOOP > ? ?2 WHILELOOP > ? ?1 CASE > > Now there are 3 FOREACHLOOP's :) Yowza! For each gained more than the regular loop :-) Maurizio > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From kasperni at gmail.com Thu Oct 17 15:08:38 2024 From: kasperni at gmail.com (Kasper Nielsen) Date: Thu, 17 Oct 2024 20:38:38 +0530 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: Hi, I know this feature has been requested a number of times. But I want to add one more usecase. There is common pattern in many frameworks of specifying a factory class in an annotation a.la. @SomeFrameworkAnnotation(factory = MyAppFactory.class) Unfortunately, this pattern requires some more effort, if you want to use it together with modules. Either you need to open the package or handoff a Lookup object to the framework in some way. While this isn't super complicated, it would ease the on-ramp if you could simply use @SomeFrameworkAnnotation(factory = MyAppFactory::new) I know this type of "annotation programming" aren't really used in the JDK, but in Java's wider ecosystem I see it a lot. Best, Kasper > Idea: What about allowing lambda values for Class-valued annotation > properties when the Class is a functional interface? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Oct 17 16:01:26 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 Oct 2024 12:01:26 -0400 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: Yes, this is a frequent request. And our analysis of this remains: it is reasonable from a linguistic point of view, but the implementation is hellaciously intrusive (as it cuts through all the layers mentioned), and so ends up having a relatively poor return-on-investment compared to other improvements. On 10/17/2024 11:08 AM, Kasper Nielsen wrote: > Hi, I know this feature has been requested a number of times. But I > want to add one more usecase. There is common pattern in many > frameworks of specifying a factory class in an annotation a.la > . > > ?@SomeFrameworkAnnotation(factory = MyAppFactory.class) > > Unfortunately, this pattern requires some more effort, if you want to > use it together with modules. Either you need to open the package or > handoff a Lookup object to the framework in some way. While this isn't > super complicated, it would ease the on-ramp if you could simply use > > ?@SomeFrameworkAnnotation(factory = MyAppFactory::new) > > ?I know this type of "annotation programming" aren't really used in > the JDK, but in Java's wider ecosystem I see it a lot. > > ?Best, Kasper > > > Idea: What about allowing lambda values for Class-valued > annotation properties when the Class is a functional interface? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cushon at google.com Thu Oct 17 17:12:12 2024 From: cushon at google.com (Liam Miller-Cushon) Date: Thu, 17 Oct 2024 10:12:12 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> Message-ID: I analyzed a sample of code using the changes at 08c8b1f3c64. I can re-analyze with the latest version, but the initial results were: 120 METHODDEF 74 IF 44 FORLOOP 13 WHILELOOP 10 TRY 5 FOREACHLOOP 2 DOLOOP 1 LAMBDA On Thu, Oct 17, 2024 at 8:08?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > > On 17/10/2024 16:03, Archie Cobbs wrote: > > On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> Funny to see the FOREACHLOOP popping out. This code is (at least) from 17 >> years ago (!!) and predates any form of effectively final analysis - back >> then even for-each required to hoist the variable in a separate final >> one :-) >> > > I was wondering about that as well. I didn't realize that there was a > point where foreach() already existed and this effectively final tweak was > added. I don't see a relevant JEP, did it predate the JEP process? > > Effectively final support was added as part of Java 8 and Project Lambda. > Java 7 also had some bits of effective finality here and there, but Java 8 > is what sealed the deal. Back then we did not have the JEP process. > > > >> I realize, the important info is not where the dummy variable is >> declared. It's the declaration of the variable it points to in the >> initializer that matters! >> > > D'oh, yes of course... easy to fix though. > > Thanks > > > Here are the new stats - these look more like what one might expect: > > 87 METHODDEF > 11 FORLOOP > 3 TRY > 3 IF > 3 FOREACHLOOP > 3 DOLOOP > 2 WHILELOOP > 1 CASE > > Now there are 3 FOREACHLOOP's :) > > Yowza! For each gained more than the regular loop :-) > > Maurizio > > > -Archie > > -- > Archie L. Cobbs > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Oct 17 17:14:08 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 17 Oct 2024 13:14:08 -0400 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> Message-ID: I'm guessing, too, that many of those IFs really are hiding METHODDEF or FORLOOP? On 10/17/2024 1:12 PM, Liam Miller-Cushon wrote: > I analyzed a sample of code using the changes at?08c8b1f3c64. I can > re-analyze with the latest version,?but the initial results were: > > ? ? 120 METHODDEF > ? ? ?74 IF > ? ? ?44 FORLOOP > ? ? ?13 WHILELOOP > ? ? ?10 TRY > ? ? ? 5 FOREACHLOOP > ? ? ? 2 DOLOOP > ? ? ? 1 LAMBDA > > > On Thu, Oct 17, 2024 at 8:08?AM Maurizio Cimadamore > wrote: > > > On 17/10/2024 16:03, Archie Cobbs wrote: >> On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore >> wrote: >> >> Funny to see the FOREACHLOOP popping out. This code is (at >> least) from 17 years ago (!!) and predates any form of >> effectively final analysis - back then even for-each required >> to hoist the variable in a separate |final| one :-) >> >> >> I was wondering about that as well. I didn't realize that there >> was a point where foreach() already existed and this effectively >> final tweak was added. I don't see a relevant JEP, did it predate >> the JEP process? > Effectively final support was added as part of Java 8 and Project > Lambda. Java 7 also had some bits of effective finality here and > there, but Java 8 is what sealed the deal. Back then we did not > have the JEP process. >> >> I realize, the important info is not where the dummy variable >> is declared. It's the declaration of the variable it points >> to in the initializer that matters! >> >> >> D'oh, yes of course... easy to fix though. > Thanks >> >> Here are the new stats - these look more like what one might expect: >> >> ? 87 METHODDEF >> ? 11 FORLOOP >> ? ?3 TRY >> ? ?3 IF >> ? ?3 FOREACHLOOP >> ? ?3 DOLOOP >> ? ?2 WHILELOOP >> ? ?1 CASE >> >> Now there are 3 FOREACHLOOP's :) > > Yowza! For each gained more than the regular loop :-) > > Maurizio > >> >> -Archie >> >> -- >> Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Oct 17 17:18:12 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 17 Oct 2024 18:18:12 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> Message-ID: <45ec5a0d-1b18-4425-8b20-1d7ed3737ce1@oracle.com> I believe in the new patch Archie has, IF means IF (e.g. the variable we are snapshotting is declared in the if statement). But since Liam was using an earlier iteration, it is possible that the results here are a bit skewed. (Thanks Liam!) Maurizio On 17/10/2024 18:14, Brian Goetz wrote: > I'm guessing, too, that many of those IFs really are hiding METHODDEF > or FORLOOP? > > > On 10/17/2024 1:12 PM, Liam Miller-Cushon wrote: >> I analyzed a sample of code using the changes at?08c8b1f3c64. I can >> re-analyze with the latest version,?but the initial results were: >> >> ? ? 120 METHODDEF >> ? ? ?74 IF >> ? ? ?44 FORLOOP >> ? ? ?13 WHILELOOP >> ? ? ?10 TRY >> ? ? ? 5 FOREACHLOOP >> ? ? ? 2 DOLOOP >> ? ? ? 1 LAMBDA >> >> >> On Thu, Oct 17, 2024 at 8:08?AM Maurizio Cimadamore >> wrote: >> >> >> On 17/10/2024 16:03, Archie Cobbs wrote: >>> On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore >>> wrote: >>> >>> Funny to see the FOREACHLOOP popping out. This code is (at >>> least) from 17 years ago (!!) and predates any form of >>> effectively final analysis - back then even for-each >>> required to hoist the variable in a separate |final| one :-) >>> >>> >>> I was wondering about that as well. I didn't realize that there >>> was a point where foreach() already existed and this effectively >>> final tweak was added. I don't see a relevant JEP, did it >>> predate the JEP process? >> Effectively final support was added as part of Java 8 and Project >> Lambda. Java 7 also had some bits of effective finality here and >> there, but Java 8 is what sealed the deal. Back then we did not >> have the JEP process. >>> >>> I realize, the important info is not where the dummy >>> variable is declared. It's the declaration of the variable >>> it points to in the initializer that matters! >>> >>> >>> D'oh, yes of course... easy to fix though. >> Thanks >>> >>> Here are the new stats - these look more like what one might expect: >>> >>> ? 87 METHODDEF >>> ? 11 FORLOOP >>> ? ?3 TRY >>> ? ?3 IF >>> ? ?3 FOREACHLOOP >>> ? ?3 DOLOOP >>> ? ?2 WHILELOOP >>> ? ?1 CASE >>> >>> Now there are 3 FOREACHLOOP's :) >> >> Yowza! For each gained more than the regular loop :-) >> >> Maurizio >> >>> >>> -Archie >>> >>> -- >>> Archie L. Cobbs >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cushon at google.com Fri Oct 18 00:07:28 2024 From: cushon at google.com (Liam Miller-Cushon) Date: Thu, 17 Oct 2024 17:07:28 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <45ec5a0d-1b18-4425-8b20-1d7ed3737ce1@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> <45ec5a0d-1b18-4425-8b20-1d7ed3737ce1@oracle.com> Message-ID: I redid the sample with the latest patch, and as expected got fewer IFs: 165 METHODDEF 31 FORLOOP 9 IF 7 TRY 6 INIT 4 WHILELOOP 3 FOREACHLOOP 1 LAMBDA On Thu, Oct 17, 2024 at 10:18?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > I believe in the new patch Archie has, IF means IF (e.g. the variable we > are snapshotting is declared in the if statement). > > But since Liam was using an earlier iteration, it is possible that the > results here are a bit skewed. > > (Thanks Liam!) > > Maurizio > On 17/10/2024 18:14, Brian Goetz wrote: > > I'm guessing, too, that many of those IFs really are hiding METHODDEF or > FORLOOP? > > > On 10/17/2024 1:12 PM, Liam Miller-Cushon wrote: > > I analyzed a sample of code using the changes at 08c8b1f3c64. I can > re-analyze with the latest version, but the initial results were: > > 120 METHODDEF > 74 IF > 44 FORLOOP > 13 WHILELOOP > 10 TRY > 5 FOREACHLOOP > 2 DOLOOP > 1 LAMBDA > > > On Thu, Oct 17, 2024 at 8:08?AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> >> On 17/10/2024 16:03, Archie Cobbs wrote: >> >> On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore < >> maurizio.cimadamore at oracle.com> wrote: >> >>> Funny to see the FOREACHLOOP popping out. This code is (at least) from >>> 17 years ago (!!) and predates any form of effectively final analysis - >>> back then even for-each required to hoist the variable in a separate >>> final one :-) >>> >> >> I was wondering about that as well. I didn't realize that there was a >> point where foreach() already existed and this effectively final tweak was >> added. I don't see a relevant JEP, did it predate the JEP process? >> >> Effectively final support was added as part of Java 8 and Project Lambda. >> Java 7 also had some bits of effective finality here and there, but Java 8 >> is what sealed the deal. Back then we did not have the JEP process. >> >> >> >>> I realize, the important info is not where the dummy variable is >>> declared. It's the declaration of the variable it points to in the >>> initializer that matters! >>> >> >> D'oh, yes of course... easy to fix though. >> >> Thanks >> >> >> Here are the new stats - these look more like what one might expect: >> >> 87 METHODDEF >> 11 FORLOOP >> 3 TRY >> 3 IF >> 3 FOREACHLOOP >> 3 DOLOOP >> 2 WHILELOOP >> 1 CASE >> >> Now there are 3 FOREACHLOOP's :) >> >> Yowza! For each gained more than the regular loop :-) >> >> Maurizio >> >> >> -Archie >> >> -- >> Archie L. Cobbs >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Fri Oct 18 02:48:10 2024 From: davidalayachew at gmail.com (David Alayachew) Date: Thu, 17 Oct 2024 22:48:10 -0400 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: Thank you for your response Brian. Very informative, I appreciate it. You definitely read my intent. I now agree, keeping the border where it is makes the most sense. There are other ways to achieve what I want, so I will go with those for now. And like you mentioned, feasability aside, this will wreck people's mental model. Cutting it short makes things significantly easier and cleaner. And thank you for your response Archie. I was more speaking to annotations that only support String values. The vast majority of annotations seem to fall under that case, including the one I want to work with. I understand that it is not the strongest argument, which is why I just wanted to see the downsides of the idea. As for your idea, I quite like it. No idea about the viability though. On Thu, Oct 17, 2024, 12:01?PM Brian Goetz wrote: > Yes, this is a frequent request. And our analysis of this remains: it is > reasonable from a linguistic point of view, but the implementation is > hellaciously intrusive (as it cuts through all the layers mentioned), and > so ends up having a relatively poor return-on-investment compared to other > improvements. > > > On 10/17/2024 11:08 AM, Kasper Nielsen wrote: > > Hi, I know this feature has been requested a number of times. But I want > to add one more usecase. There is common pattern in many frameworks of > specifying a factory class in an annotation a.la. > > @SomeFrameworkAnnotation(factory = MyAppFactory.class) > > Unfortunately, this pattern requires some more effort, if you want to use > it together with modules. Either you need to open the package or handoff a > Lookup object to the framework in some way. While this isn't super > complicated, it would ease the on-ramp if you could simply use > > @SomeFrameworkAnnotation(factory = MyAppFactory::new) > > I know this type of "annotation programming" aren't really used in the > JDK, but in Java's wider ecosystem I see it a lot. > > Best, Kasper > > >> Idea: What about allowing lambda values for Class-valued annotation >> properties when the Class is a functional interface? >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Fri Oct 18 06:38:39 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 18 Oct 2024 08:38:39 +0200 (CEST) Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: References: Message-ID: <820849169.42347868.1729233519081.JavaMail.zimbra@univ-eiffel.fr> > From: "Kasper Nielsen" > To: "Archie Cobbs" > Cc: "David Alayachew" , "amber-dev" > > Sent: Thursday, October 17, 2024 5:08:38 PM > Subject: Re: Are there any downsides if we add Enum.name() to the list of > constant expressions in the JLS? > Hi, I know this feature has been requested a number of times. But I want to add > one more usecase. There is common pattern in many frameworks of specifying a > factory class in an annotation [ http://a.la/ | a.la ] . > @SomeFrameworkAnnotation(factory = MyAppFactory.class) > Unfortunately, this pattern requires some more effort, if you want to use it > together with modules. Either you need to open the package or handoff a Lookup > object to the framework in some way. While this isn't super complicated, it > would ease the on-ramp if you could simply use > @SomeFrameworkAnnotation(factory = MyAppFactory::new) > I know this type of "annotation programming" aren't really used in the JDK, but > in Java's wider ecosystem I see it a lot. And this is not necessary a good thing. With my teacher hat, using annotations for the configuration usually means that the configuration is scattered into several files and and which make it hard to find/understand, fixing configuration issues in student enterprisy code is a pain because of that. So i've no problem with annotations being used to specify additional semantics @Entity, @Transactional etc but using annotations for specifying configuration, for me, is a step too far. > Best, Kasper R?mi >> Idea: What about allowing lambda values for Class-valued annotation properties >> when the Class is a functional interface? -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Fri Oct 18 09:13:45 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 18 Oct 2024 10:13:45 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <6e14d6b9-7c04-412f-aa43-d739a56e23f3@oracle.com> <2ea7b7cc-6ccb-4dd1-ac7d-7e5b8132e368@oracle.com> <45ec5a0d-1b18-4425-8b20-1d7ed3737ce1@oracle.com> Message-ID: Thanks Liam! Do you have a way to measure how many for loops there are in your code base? (It's ok if not) Maurizio On 18/10/2024 01:07, Liam Miller-Cushon wrote: > I redid the sample with the latest patch, and as expected got fewer IFs: > > ? ? 165 METHODDEF > ? ? ?31 FORLOOP > ? ? ? 9 IF > ? ? ? 7 TRY > ? ? ? 6 INIT > ? ? ? 4 WHILELOOP > ? ? ? 3 FOREACHLOOP > ? ? ? 1 LAMBDA > > On Thu, Oct 17, 2024 at 10:18?AM Maurizio Cimadamore > wrote: > > I believe in the new patch Archie has, IF means IF (e.g. the > variable we are snapshotting is declared in the if statement). > > But since Liam was using an earlier iteration, it is possible that > the results here are a bit skewed. > > (Thanks Liam!) > > Maurizio > > On 17/10/2024 18:14, Brian Goetz wrote: >> I'm guessing, too, that many of those IFs really are hiding >> METHODDEF or FORLOOP? >> >> >> On 10/17/2024 1:12 PM, Liam Miller-Cushon wrote: >>> I analyzed a sample of code using the changes at?08c8b1f3c64. I >>> can re-analyze with the latest version,?but the initial results >>> were: >>> >>> ? ? 120 METHODDEF >>> ? ? ?74 IF >>> ? ? ?44 FORLOOP >>> ? ? ?13 WHILELOOP >>> ? ? ?10 TRY >>> ? ? ? 5 FOREACHLOOP >>> ? ? ? 2 DOLOOP >>> ? ? ? 1 LAMBDA >>> >>> >>> On Thu, Oct 17, 2024 at 8:08?AM Maurizio Cimadamore >>> wrote: >>> >>> >>> On 17/10/2024 16:03, Archie Cobbs wrote: >>>> On Thu, Oct 17, 2024 at 5:34?AM Maurizio Cimadamore >>>> wrote: >>>> >>>> Funny to see the FOREACHLOOP popping out. This code is >>>> (at least) from 17 years ago (!!) and predates any form >>>> of effectively final analysis - back then even for-each >>>> required to hoist the variable in a separate |final| >>>> one :-) >>>> >>>> >>>> I was wondering about that as well. I didn't realize that >>>> there was a point where foreach() already existed and this >>>> effectively final tweak was added. I don't see a relevant >>>> JEP, did it predate the JEP process? >>> Effectively final support was added as part of Java 8 and >>> Project Lambda. Java 7 also had some bits of effective >>> finality here and there, but Java 8 is what sealed the deal. >>> Back then we did not have the JEP process. >>>> >>>> I realize, the important info is not where the dummy >>>> variable is declared. It's the declaration of the >>>> variable it points to in the initializer that matters! >>>> >>>> >>>> D'oh, yes of course... easy to fix though. >>> Thanks >>>> >>>> Here are the new stats - these look more like what one >>>> might expect: >>>> >>>> 87 METHODDEF >>>> ? 11 FORLOOP >>>> ? ?3 TRY >>>> ? ?3 IF >>>> ? ?3 FOREACHLOOP >>>> ? ?3 DOLOOP >>>> ? ?2 WHILELOOP >>>> ? ?1 CASE >>>> >>>> Now there are 3 FOREACHLOOP's :) >>> >>> Yowza! For each gained more than the regular loop :-) >>> >>> Maurizio >>> >>>> >>>> -Archie >>>> >>>> -- >>>> Archie L. Cobbs >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From kan.izh at gmail.com Fri Oct 18 10:56:20 2024 From: kan.izh at gmail.com (Anatoly Kupriyanov) Date: Fri, 18 Oct 2024 11:56:20 +0100 Subject: Are there any downsides if we add Enum.name() to the list of constant expressions in the JLS? In-Reply-To: <820849169.42347868.1729233519081.JavaMail.zimbra@univ-eiffel.fr> References: <820849169.42347868.1729233519081.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Agree. Placing an executable code into annotations sounds quite wild. I could not imagine how should stack trace look like... Or adding a break point?.. debugger? IDE refactorings? Code coverage tools? Too much magic. No, thank you. On Fri, 18 Oct 2024, 10:33 Remi Forax, wrote: > > > ------------------------------ > > *From: *"Kasper Nielsen" > *To: *"Archie Cobbs" > *Cc: *"David Alayachew" , "amber-dev" < > amber-dev at openjdk.org> > *Sent: *Thursday, October 17, 2024 5:08:38 PM > *Subject: *Re: Are there any downsides if we add Enum.name() to the list > of constant expressions in the JLS? > > Hi, I know this feature has been requested a number of times. But I want > to add one more usecase. There is common pattern in many frameworks of > specifying a factory class in an annotation a.la. > > @SomeFrameworkAnnotation(factory = MyAppFactory.class) > > Unfortunately, this pattern requires some more effort, if you want to use > it together with modules. Either you need to open the package or handoff a > Lookup object to the framework in some way. While this isn't super > complicated, it would ease the on-ramp if you could simply use > > @SomeFrameworkAnnotation(factory = MyAppFactory::new) > > I know this type of "annotation programming" aren't really used in the > JDK, but in Java's wider ecosystem I see it a lot. > > > And this is not necessary a good thing. > > With my teacher hat, using annotations for the configuration usually means > that the configuration is scattered into several files and and which make > it hard to find/understand, fixing configuration issues in student > enterprisy code is a pain because of that. > > So i've no problem with annotations being used to specify additional > semantics @Entity, @Transactional etc but using annotations for specifying > configuration, for me, is a step too far. > > > Best, Kasper > > > R?mi > > > >> Idea: What about allowing lambda values for Class-valued annotation >> properties when the Class is a functional interface? >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Sat Oct 19 17:14:12 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Sat, 19 Oct 2024 12:14:12 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: On Wed, Oct 16, 2024 at 8:56?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > An intersting angle we discussed was whether we feel imperative for loops > are special enough to deserve special treatment, or whether this is the > start of a loosening process that will eventually lead to allow capture for > every local variable *value*. > (Caveat: statements below are under the aegis of an assumed "loosening process" discussion, and is agnostic on whether a "loosening process" discussion is itself worthwhile :) FWIW, it occurred to me that there might be another option worth considering on the "effectively final" spectrum that has not been mentioned (AFAIK). The problem that "effectively final" tries to solve is the ambiguity that arises when a variable is both (a) captured by some code that will execute later (asynchronously) and yet (b) modified synchronously (i.e., outside of the capturing code). The key observation here is that the problem is much more acute when the variable is modified *after* the capture. For example, this: int x = 42; Runnable r = () -> System.out.println(x); if (squareit) x = x * x; seems a lot worse in terms of ambiguity/confusing semantics than this: int x = 42; if (squareit) x = x * x; Runnable r = () -> System.out.println(x); But wait... what exactly is the meaning of the word "after" in that observation? Does "after" mean "later in time as the program executes" or simply "lexically later in the source code of the program"? I would claim that the definition of "after" that most closely matches programmer intuition is the latter - "lexically later in the source code of the program". As an example of this, look no farther than the basic for() loop we have been discussing. This example: for (int i = 1; i <=3; i++) { Runnable r = () -> System.out.println(i); if (squareit) i = i * i; } seems a lot worse in terms of ambiguity/confusing semantics than this one: for (int i = 1; i <=3; i++) { if (squareit) i = i * i; Runnable r = () -> System.out.println(i); } Even though in both cases variable i is modified "later in time when the program executes". Note that this would work for any type of loop, not just with for() loops, as well as plain code. This leads to a broader possible "loosening", which would simply state: a variable can be captured by a lambda only if it is not modified at any point lexically following the lambda in the source code. Of course, this would require replacing the term "effectively final" with... "effectively frozen"? :) I was curious about the stats on this so I modified the "dummy finder" to report whether or not, for each dummy variable reported, the original variable was modified after the capturing lambda. Here's the results when run against the JDK: 63 METHODDEF (original modified before) 20 METHODDEF (original never modified) 11 FORLOOP (original modified before) 5 METHODDEF (original modified after) 3 TRY (original modified before) 3 IF (original modified before) 3 DOLOOP (original modified before) 2 WHILELOOP (original modified before) 2 FOREACHLOOP (original never modified) 1 FOREACHLOOP (original modified before) 1 CASE (original modified before) Note that out of 114 examples, there are only 5 with "original modified after": (example ). This augurs well for the usefulness of "effectively frozen". The other 22 outliers are "original never modified", which means the dummy variable is unnecessary because the original is never modified. There are 2 of these in FOREACHLOOP, which are probably leftovers from when for-each didn't have its special rule; the remaining 20 are in METHODEF (example ) and these are just opportunities for small cleanups. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 09:48:43 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2024 10:48:43 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> Message-ID: <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> Interesting observation. On 19/10/2024 18:14, Archie Cobbs wrote: > But wait... what exactly is the meaning of the word "after" in that > observation? Does "after" mean "later in time as the program executes" > or simply "lexically later in the source code of the program"? I agree with your subjective feeling that the latter seems to be more important when reading the code. But, as you observed, for loops are still kind of problematic here, because the space vs. time conflict: e.g. even though a loop variable might not be modified after it is captured in a loop body, you can still see ?previous values? of the captured variable, exposed via previous capturing lambdas. I also wonder if saying that all that matters is the ?space? dimension (e.g. where variable references occur lexically, in a program) would create asymmetries with some of the other flow-dependent analyses we do. For instance, DA/DU does not treat the loop body in a truly lexical fashion - e.g. something like this is an error: |final int x; while (loopCond) { x = 1; } | This might look good if the ?time? dimension didn?t exist. But DA/DU takes time into account, and detects that |x| might be actually assigned twice. In other words, to me the crux of the problem remains the definition of the loop induction variable. We want to carve out some special rules that allow us to treat the loop induction variable /as if/ it was a variable freshly declared inside the loop body (e.g. meaning that the assignment we see in the STEP part of the loop doesn?t really affect whether that variable can be captured or not). That seems kind of an orthogonal extension to the one you are proposing here - surely, ?effectively frozen? will allow capture for far more locals (as your finder experiments show), but we still need to somehow be able to special case the treatment for loop induction variables. Maurizio ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Oct 21 14:39:03 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 21 Oct 2024 09:39:03 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> Message-ID: On Mon, Oct 21, 2024 at 4:48?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > In other words, to me the crux of the problem remains the definition of > the loop induction variable. We want to carve out some special rules that > allow us to treat the loop induction variable *as if* it was a variable > freshly declared inside the loop body (e.g. meaning that the assignment we > see in the STEP part of the loop doesn?t really affect whether that > variable can be captured or not). > > That seems kind of an orthogonal extension to the one you are proposing > here - surely, ?effectively frozen? will allow capture for far more locals > (as your finder experiments show), but we still need to somehow be able to > special case the treatment for loop induction variables. > I'm saying something different from that... and also simpler. Let's restate the conjecture: Suppose we changed the requirement for lambda capture of a variable from "final or effectively final" to "final or effectively frozen at the point of capture", where "effectively frozen at the point of capture" means there are no mutations to the variable that lexically follow the capturing lambda. Then this would clearly subsume what's proposed in JDK-8341785 (basic for() loop variables are capturable) - it's a strict expansion of that. So no special treatment of loop induction variables is needed. Not only that, even though it's broader, it's a much simpler requirement that has no dependence on DA/DU analysis or any kind of flow analysis. So I'm saying that this "space" interpretation - which is strictly lexical - is superior because it has all of the following nice attributes: - It solves the original problem - allow capture of basic for() loop variables mutated only in the loop header - It also solves a much wider set of "dummy variable" cases in other code (e.g., do and while loops, and all but 5 of the METHODREF examples in the JDK) - Yet it still seems to closely match developer intuition - or at least, no less closely than the previous more limited basic for() loop proposal does - It is very simple to specify and understand The upshot is: If one were to evaluate possible replacements for the "final or effectively final" requirement for variable capture, in my opinion this would be a promising option - and in particular has a much higher cost/benefit ratio than the earlier proposal of just addressing basic for() loop variables. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 15:01:18 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2024 16:01:18 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> Message-ID: <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> On 21/10/2024 15:39, Archie Cobbs wrote: > I'm saying something different from that... and also simpler. > > Let's restate the conjecture: Suppose we changed the requirement for > lambda capture of a variable from "final or effectively final" to > "final or effectively frozen at the point of capture", where > "effectively frozen at the point of capture" means there are no > mutations to the variable that lexically follow the capturing lambda. > > Then this would clearly subsume what's proposed in JDK-8341785 (basic > for() loop variables are capturable) - it's a strict expansion of that. > > So no special treatment of loop induction variables is needed. I?m not sure of that. I mean, I ?can see? why you?d think that. But in which scope does STEP belong? Yes, it belongs to the for loop header - but it is executed /after/ the loop. And, in fact, it can even refer to variables that would otherwise be DU outside the loop body: |void m() { int i; for (int j = 0 ; j < 10 ; j = j + i) { i = 1; // if this is commented out, error! } } | So I?m not sure it is a /strict/ generalization :-) Maurizio > > Not only that, even though it's broader, it's a much simpler > requirement that has no dependence on DA/DU analysis or any kind of > flow analysis. > > So I'm saying that this "space" interpretation - which is strictly > lexical - is superior because it has all of the following nice attributes: > > * It solves the original problem - allow capture of basic for() loop > variables mutated only in the loop header > * It also solves a much wider set of "dummy variable" cases in other > code (e.g., do and while loops, and all but 5 of the METHODREF > examples in the JDK) > * Yet it still seems to closely match developer intuition - or at > least, no less closely than the previous more limited basic for() > loop proposal does > * It is very simple to specify and understand > > The upshot is: If one were to evaluate possible replacements for the > "final or effectively final" requirement for variable capture, in my > opinion this would be a promising option - and in particular has a > much higher cost/benefit ratio than the earlier proposal of just > addressing basic for() loop variables. ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Oct 21 15:08:44 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 21 Oct 2024 10:08:44 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> Message-ID: On Mon, Oct 21, 2024 at 10:01?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > On 21/10/2024 15:39, Archie Cobbs wrote: > > So no special treatment of loop induction variables is needed. > > I?m not sure of that. I mean, I ?can see? why you?d think that. But in > which scope does STEP belong? Yes, it belongs to the for loop header - but > it is executed *after* the loop. And, in fact, it can even refer to > variables that would otherwise be DU outside the loop body: > > void m() { > int i; > for (int j = 0 ; j < 10 ; j = j + i) { > i = 1; // if this is commented out, error! > } > } > > So I?m not sure it is a *strict* generalization :-) > Sorry for not being more precise... all that I am implying by "generalization" is this: - Let X be a program X that currently does not compile, but would successfully compile under the proposal in JDK-8341785 (allow capture of basic for() loop variables) - Then X would also compile under the "final or effectively frozen at the point of capture" proposal Proof: Let v be the variable. It must be the case that v is not modified in the body of the for() loop. It must also be the case that v is not modified after the for() loop, because v is declared in the for() loop INIT section. It must also be the case that the lambda is contained in the body of the for() loop. Therefore, it is not possible for v to be modified at any point in the source code of the program that lexically follows the lambda. Therefore v is final or effectively frozen at the point of capture" with respect to that lambda. -AC -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 15:16:35 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2024 16:16:35 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> Message-ID: On 21/10/2024 16:08, Archie Cobbs wrote: > On Mon, Oct 21, 2024 at 10:01?AM Maurizio Cimadamore > wrote: > > On 21/10/2024 15:39, Archie Cobbs wrote: > >> So no special treatment of loop induction variables is needed. > > I?m not sure of that. I mean, I ?can see? why you?d think that. > But in which scope does STEP belong? Yes, it belongs to the for > loop header - but it is executed /after/ the loop. And, in fact, > it can even refer to variables that would otherwise be DU outside > the loop body: > > |void m() { int i; for (int j = 0 ; j < 10 ; j = j + i) { i = 1; > // if this is commented out, error! } } | > > So I?m not sure it is a /strict/ generalization :-) > > Sorry for not being more precise... all that I am implying by > "generalization" is this: > > * Let X be a program X that currently does not compile, but would > successfully compile under the proposal in JDK-8341785 (allow > capture of basic for() loop variables) > * Then X would also compile under the "final or effectively frozen > at the point of capture" proposal > > Proof: Let v be the variable. It must be the case that v is not > modified in the body of the for() loop. It must also be the case that > v is not modified after the for() loop, because v is declared in the > for()? loop INIT section. It must also be the case that the lambda is > contained in the body of the for() loop. Therefore, it is not possible > for v to be modified at any point in the source code of the program > that lexically follows the lambda. Therefore v is final or effectively > frozen at the point of capture" with respect to that lambda. I get that! What I'm saying is that most users will read my above example like: |for (int j = 0 ; j < 10 ; ) { ... j = j + i; } | That is a good explanation for what the loop does. But this now breaks the generalization (because "j" is now mutated inside the body). E.g. the variable "j" is declared in the "for loop" statement. It is also modified in the for loop statement (in the STEP part). It seems mostly an implementation "trick" that we can look at STEP before BODY, so that we can then consider the induction variable as "not mutated after it is introduced". Maurizio > -AC > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Oct 21 15:51:36 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 21 Oct 2024 10:51:36 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> Message-ID: On Mon, Oct 21, 2024 at 10:16?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > I get that! What I'm saying is that most users will read my above example > like: > > for (int j = 0 ; j < 10 ; ) { > > ... > j = j + i; > } > > That is a good explanation for what the loop does. But this now breaks the > generalization (because "j" is now mutated inside the body). E.g. the > variable "j" is declared in the "for loop" statement. It is also modified > in the for loop statement (in the STEP part). It seems mostly an > implementation "trick" that we can look at STEP before BODY, so that we can > then consider the induction variable as "not mutated after it is > introduced". > Yes but I think this "trick" is appropriate because it aligns with how developers intuitively view this whole issue. In other words, the following two examples may be equivalent in terms of DA/DU analysis, but they are not the same in terms of how ambiguous they seem to the developer: Example A: for (int i = 0; i < 10; i++) { Runnable r = () -> System.out.println(i); } Example B: for (int i = 0; i < 10; ) { Runnable r = () -> System.out.println(i); i++; } I am claiming that Example A is much clearer than Example B in terms of ambiguity (which is the whole problem "effectively final" was invented to solve). Now the above claim is a claim about what developers intuitively perceive, so it's fuzzy by nature and I could certainly be in the minority view here! All I can confidently say is that after thinking about it and looking at the examples in the JDK, my own developer intuition would be comfortable with an "effectively frozen at the point of capture" rule, and I would be pleased with the resulting ability to get rid of almost all of my "dummy variables". To me Example A is perfectly clear, while Example B is less clear. I'm curious what your "developer intuition" thinks. Do you look at Examples A and B and perceive them as equally ambiguous? Taking a step back, the observation that motivates the original proposal (to me at least) is that developers perceive each iteration of the body of a for() loop as its own thing, with the loop variable serving the same role as a method parameter. That is, the body of a for() loop is just a parameterized block of code - i.e., a thing we usually call a "method" - that you "invoke" multiple times, and the loop variable is the parameter. One can view a for() loop as just a special syntax for inlining a method that you want to invoke multiple times in succession with a sequence of parameter values. So just as method parameters are effectively final within their methods, so should loop variables be "effectively final" within their loop bodies. If you take that view, then Example A and Example B are clearly different. They are just as different as these two examples would be: Example C: void meth(int i) { Runnable r = () -> System.out.println(i); } for (int i = 0; i < 10; i++) meth(i); Example D: void meth(i) { Runnable r = () -> System.out.println(i); i++; } for (int i = 0; i < 10; ) { meth(i); i++; } Again, we're in the domain of "developer intuition" and "perception" so things are fuzzy... and compiler developers may not constitute a representative sample :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 16:36:24 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2024 17:36:24 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> Message-ID: <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> > > Example A: > > for (int i = 0; i < 10; i++) { > ??? Runnable r = () -> System.out.println(i); > } > > Example B: > > for (int i = 0; i < 10; ) { > ??? Runnable r = () -> System.out.println(i); > ??? i++; > } > > I am claiming that Example A is much clearer than Example B in terms > of ambiguity (which is the whole problem "effectively final" was > invented to solve). > > Now the above claim is a claim about what developers intuitively > perceive, so it's fuzzy by nature and I could certainly be in the > minority view here! > > All I can confidently say is that after thinking about it and looking > at the examples in the JDK, my own developer intuition would be > comfortable with an "effectively frozen at the point of capture" rule, > and I would be pleased with the resulting ability to get rid of almost > all of my "dummy variables". To me Example A is perfectly clear, while > Example B is less clear. > > I'm curious what your "developer intuition" thinks. Do you look at > Examples A and B and perceive them as equally ambiguous? I also find A better. What I'm trying to say is that if a developer is confused (by the i++) on what "frozen" means for a loop variable, they won't find any clarity in our explanation that "lexically scoping trumps everything else". E.g. whether a developer reads the STEP part of a loop as part of the body (after the end of the body) or not is, I believe, a very subjective thing - and one which affects how any change we make in the area will be perceived (IMHO). > > Taking a step back, the observation that motivates the original > proposal (to me at least) is that developers perceive each iteration > of the body of a for() loop as its own thing, with the loop variable > serving the same role as a method parameter. That is, the body of a > for() loop is just a parameterized block of code - i.e., a thing we > usually call a "method" - that you "invoke" multiple times, and the > loop variable is the parameter. One can view a for() loop as just a > special syntax for inlining a method that you want to invoke multiple > times in succession with a sequence of parameter values. So just as > method parameters are effectively final within their methods, so > should loop variables be "effectively final" within their loop bodies. If that is how a developer perceives a loop, I agree that either these new rules, or the old one pose no issue whatsoever. > > Again, we're in the domain of "developer intuition" and "perception" > so things are fuzzy... and compiler developers may not constitute a > representative sample :) That's what I'm a bit worried about. My general feeling is that there will be users that will find your explanation perfectly rational - and some other users who will need to find a coping mechanism as to why the += in the STEP of a for loop is to be interpreted less literally. Of course, as with every new proposed feature, we hear a lot from developers who think that the new proposal addresses a specific pain point that they thought should never existed in the first place. But we tend to hear less about a less vocal portion of users who might just be silently ok with the status quo. Or maybe, in this instance, we don't hear from them because they aren't there (although, Tagir expressed some concerns [1], so I have to assume there are such developers out there? _somewhere_ :-) ) [1] - https://mail.openjdk.org/pipermail/amber-dev/2024-September/008922.html > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Oct 21 17:00:29 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 21 Oct 2024 12:00:29 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > What I'm trying to say is that if a developer is confused (by the i++) on > what "frozen" means for a loop variable, they won't find any clarity in our > explanation that "lexically scoping trumps everything else". E.g. whether a > developer reads the STEP part of a loop as part of the body (after the end > of the body) or not is, I believe, a very subjective thing - and one which > affects how any change we make in the area will be perceived (IMHO). > Yes, if a developer is mentally cutting and pasting the STEP onto the tail of the BODY then you're right, that makes it appear as if the variable is not really "frozen". But the original basic for() proposal has the analogous problem - i.e., if a developer is mentally cutting and pasting the STEP onto the tail of the BODY, then in the original proposal the variable no longer appears to be "effectively final in the body of the loop". So it seems to me that this proposal and the original basic for() proposal suffer equally in that particular respect, and such a developer is not going to be satisfied by either of these new mental models. > Of course, as with every new proposed feature, we hear a lot from > developers who think that the new proposal addresses a specific pain point > that they thought should never existed in the first place. But we tend to > hear less about a less vocal portion of users who might just be silently ok > with the status quo. Or maybe, in this instance, we don't hear from them > because they aren't there (although, Tagir expressed some concerns [1], so > I have to assume there are such developers out there _somewhere_ :-) ) > I too would like to hear more opinions... speak up, naysayers :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Mon Oct 21 17:03:03 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Mon, 21 Oct 2024 18:03:03 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: <4ff03daa-7022-4f64-a89f-69bbcf76f907@oracle.com> On 21/10/2024 18:00, Archie Cobbs wrote: > On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore > wrote: > > What I'm trying to say is that if a developer is confused (by the > i++) on what "frozen" means for a loop variable, they won't find > any clarity in our explanation that "lexically scoping trumps > everything else". E.g. whether a developer reads the STEP part of > a loop as part of the body (after the end of the body) or not is, > I believe, a very subjective thing - and one which affects how any > change we make in the area will be perceived (IMHO). > > Yes, if a developer is mentally cutting and pasting the STEP onto the > tail of the BODY then you're right, that makes it appear as if the > variable is not really "frozen". > > But the original basic for() proposal has the analogous problem - > i.e., if a developer is mentally cutting and pasting the STEP onto the > tail of the BODY, then in the original proposal the variable no longer > appears to be "effectively final in the body of the loop". > > So it seems to me that this proposal and the original basic for() > proposal suffer equally in that particular respect, and such a > developer is not going to be satisfied by either of these new mental > models. Yes, that is what I was trying to suggest - e.g. the "generalization" might feel satisfying from an implementation (or specification) perspective - but I'm not sure it will make things more natural to grasp (for those developers who found the original proposal confusing). > > Of course, as with every new proposed feature, we hear a lot from > developers who think that the new proposal addresses a specific > pain point that they thought should never existed in the first > place. But we tend to hear less about a less vocal portion of > users who might just be silently ok with the status quo. Or maybe, > in this instance, we don't hear from them because they aren't > there (although, Tagir expressed some concerns [1], so I have to > assume there are such developers out there _somewhere_ :-) ) > > I too would like to hear more opinions... speak up, naysayers :) :-) > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb9n at gmail.com Mon Oct 21 17:21:31 2024 From: kevinb9n at gmail.com (Kevin Bourrillion) Date: Mon, 21 Oct 2024 10:21:31 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: well, uhh, "nay" :-) But seriously, I don't disagree that in Example A it's more than sufficiently unambiguous which value the developer wants. I just feel like this whole topic is uncomfortably intricate and messy, and the specific benefits of the change don't feel to me like they will ever be worth even the time that's *already* gone into discussing it, especially when (as Tagir said) what users really want is loops over ranges anyway. To me changing nothing feels like winning here, but that's just me. On Mon, Oct 21, 2024 at 10:00?AM Archie Cobbs wrote: > On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> What I'm trying to say is that if a developer is confused (by the i++) on >> what "frozen" means for a loop variable, they won't find any clarity in our >> explanation that "lexically scoping trumps everything else". E.g. whether a >> developer reads the STEP part of a loop as part of the body (after the end >> of the body) or not is, I believe, a very subjective thing - and one which >> affects how any change we make in the area will be perceived (IMHO). >> > Yes, if a developer is mentally cutting and pasting the STEP onto the tail > of the BODY then you're right, that makes it appear as if the variable is > not really "frozen". > > But the original basic for() proposal has the analogous problem - i.e., if > a developer is mentally cutting and pasting the STEP onto the tail of the > BODY, then in the original proposal the variable no longer appears to be > "effectively final in the body of the loop". > > So it seems to me that this proposal and the original basic for() proposal > suffer equally in that particular respect, and such a developer is not > going to be satisfied by either of these new mental models. > >> Of course, as with every new proposed feature, we hear a lot from >> developers who think that the new proposal addresses a specific pain point >> that they thought should never existed in the first place. But we tend to >> hear less about a less vocal portion of users who might just be silently ok >> with the status quo. Or maybe, in this instance, we don't hear from them >> because they aren't there (although, Tagir expressed some concerns [1], so >> I have to assume there are such developers out there _somewhere_ :-) ) >> > I too would like to hear more opinions... speak up, naysayers :) > > -Archie > > -- > Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From holo3146 at gmail.com Mon Oct 21 17:37:31 2024 From: holo3146 at gmail.com (Holo The Sage Wolf) Date: Mon, 21 Oct 2024 20:37:31 +0300 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: I disagree with the idea that "ranges" replace loops. It is a common to see stuff like: for(var x = buffer.read(); x != -1; x =buffer.read()) Or while((x = buffer.read()) != -1) In both cases, x is most likely (effectively) frozen inside the loop-clause, there is no reason to not treat it as (effectively) frozen. Yes it is technically possible to wrap those in Iterable, but I don't see this pattern die any time soon On Mon, 21 Oct 2024, 20:22 Kevin Bourrillion, wrote: > well, uhh, "nay" :-) > > But seriously, I don't disagree that in Example A it's more than > sufficiently unambiguous which value the developer wants. I just feel like > this whole topic is uncomfortably intricate and messy, and the specific > benefits of the change don't feel to me like they will ever be worth even > the time that's *already* gone into discussing it, especially when (as > Tagir said) what users really want is loops over ranges anyway. > > To me changing nothing feels like winning here, but that's just me. > > > On Mon, Oct 21, 2024 at 10:00?AM Archie Cobbs > wrote: > >> On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore < >> maurizio.cimadamore at oracle.com> wrote: >> >>> What I'm trying to say is that if a developer is confused (by the i++) >>> on what "frozen" means for a loop variable, they won't find any clarity in >>> our explanation that "lexically scoping trumps everything else". E.g. >>> whether a developer reads the STEP part of a loop as part of the body >>> (after the end of the body) or not is, I believe, a very subjective thing - >>> and one which affects how any change we make in the area will be perceived >>> (IMHO). >>> >> Yes, if a developer is mentally cutting and pasting the STEP onto the >> tail of the BODY then you're right, that makes it appear as if the variable >> is not really "frozen". >> >> But the original basic for() proposal has the analogous problem - i.e., >> if a developer is mentally cutting and pasting the STEP onto the tail of >> the BODY, then in the original proposal the variable no longer appears to >> be "effectively final in the body of the loop". >> >> So it seems to me that this proposal and the original basic for() >> proposal suffer equally in that particular respect, and such a developer is >> not going to be satisfied by either of these new mental models. >> >>> Of course, as with every new proposed feature, we hear a lot from >>> developers who think that the new proposal addresses a specific pain point >>> that they thought should never existed in the first place. But we tend to >>> hear less about a less vocal portion of users who might just be silently ok >>> with the status quo. Or maybe, in this instance, we don't hear from them >>> because they aren't there (although, Tagir expressed some concerns [1], so >>> I have to assume there are such developers out there _somewhere_ :-) ) >>> >> I too would like to hear more opinions... speak up, naysayers :) >> >> -Archie >> >> -- >> Archie L. Cobbs >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Oct 21 17:53:39 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 21 Oct 2024 13:53:39 -0400 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: <65393287-0b1c-4b7c-9bc9-43766bb1eb3c@oracle.com> I've noticed people often use the word "common" when they mean something else.? This is usually relative to their own personal experience: "I commonly see..." But that doesn't necessarily make them "common"; if you did a query over all of Github, the percentage of loops that are of this "common" idiom would surely be ... vanishingly uncommon. I think what you mean is "not unheard of". On 10/21/2024 1:37 PM, Holo The Sage Wolf wrote: > > I disagree with the idea that "ranges" replace loops. > > It is a common to see stuff like: > > for(var x = buffer.read(); x != -1; x =buffer.read()) > > Or > > while((x = buffer.read()) != -1) > > In both cases, x is most likely (effectively) frozen inside the > loop-clause, there is no reason to not treat it as (effectively) frozen. > > > Yes it is technically possible to wrap those in Iterable, but I don't > see this pattern die any time soon > > > On Mon, 21 Oct 2024, 20:22 Kevin Bourrillion, wrote: > > well, uhh, "nay" :-) > > But seriously, I don't disagree that in Example A it's more than > sufficiently unambiguous which value?the developer wants. I just > feel like this whole topic is uncomfortably intricate and messy, > and the specific benefits of the change don't feel to me like they > will ever be worth even the time that's /already/?gone into > discussing it, especially when (as Tagir said) what users really > want is loops over ranges anyway. > > To me changing nothing feels like winning here, but that's just me. > > > On Mon, Oct 21, 2024 at 10:00?AM Archie Cobbs > wrote: > > On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore > wrote: > > What I'm trying to say is that if a developer is confused > (by the i++) on what "frozen" means for a loop variable, > they won't find any clarity in our explanation that > "lexically scoping trumps everything else". E.g. whether a > developer reads the STEP part of a loop as part of the > body (after the end of the body) or not is, I believe, a > very subjective thing - and one which affects how any > change we make in the area will be perceived (IMHO). > > Yes, if a developer is mentally cutting and pasting the STEP > onto the tail of the BODY then you're right, that makes it > appear as if the variable is not really "frozen". > > But the original basic for() proposal has the analogous > problem - i.e., if a developer is mentally cutting and pasting > the STEP onto the tail of the BODY, then in the original > proposal the variable no longer appears to be "effectively > final in the body of the loop". > > So it seems to me that this proposal and the original basic > for() proposal suffer equally in that particular respect, and > such a developer is not going to be satisfied by either of > these new mental models. > > Of course, as with every new proposed feature, we hear a > lot from developers who think that the new proposal > addresses a specific pain point that they thought should > never existed in the first place. But we tend to hear less > about a less vocal portion of users who might just be > silently ok with the status quo. Or maybe, in this > instance, we don't hear from them because they aren't > there (although, Tagir expressed some concerns [1], so I > have to assume there are such developers out there? > _somewhere_ :-) ) > > I too would like to hear more opinions... speak up, naysayers :) > > -Archie > > -- > Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From holo3146 at gmail.com Mon Oct 21 18:07:41 2024 From: holo3146 at gmail.com (Holo The Sage Wolf) Date: Mon, 21 Oct 2024 21:07:41 +0300 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <65393287-0b1c-4b7c-9bc9-43766bb1eb3c@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <65393287-0b1c-4b7c-9bc9-43766bb1eb3c@oracle.com> Message-ID: The reason I said it is "common" is because it is something you see a lot when you search "java read from buffer" in Google (3 out of the first 5 result, including stack overflow and Baeldung post. Similarly to "java read from inputstream" (excluding the javadoc result, which doesn't have an example on how to use inputstreams) (SO and Baeldung seems to really like this pattern) So I really meant "common" when I said "common", my sample was just different from yours. But even if we disagree on the usage of "common", I still my point is still standing On Mon, 21 Oct 2024, 20:53 Brian Goetz, wrote: > I've noticed people often use the word "common" when they mean something > else. This is usually relative to their own personal experience: "I > commonly see..." But that doesn't necessarily make them "common"; if you > did a query over all of Github, the percentage of loops that are of this > "common" idiom would surely be ... vanishingly uncommon. > > I think what you mean is "not unheard of". > > > On 10/21/2024 1:37 PM, Holo The Sage Wolf wrote: > > I disagree with the idea that "ranges" replace loops. > > It is a common to see stuff like: > > for(var x = buffer.read(); x != -1; x =buffer.read()) > > Or > > while((x = buffer.read()) != -1) > > In both cases, x is most likely (effectively) frozen inside the > loop-clause, there is no reason to not treat it as (effectively) frozen. > > > Yes it is technically possible to wrap those in Iterable, but I don't see > this pattern die any time soon > > On Mon, 21 Oct 2024, 20:22 Kevin Bourrillion, wrote: > >> well, uhh, "nay" :-) >> >> But seriously, I don't disagree that in Example A it's more than >> sufficiently unambiguous which value the developer wants. I just feel like >> this whole topic is uncomfortably intricate and messy, and the specific >> benefits of the change don't feel to me like they will ever be worth even >> the time that's *already* gone into discussing it, especially when (as >> Tagir said) what users really want is loops over ranges anyway. >> >> To me changing nothing feels like winning here, but that's just me. >> >> >> On Mon, Oct 21, 2024 at 10:00?AM Archie Cobbs >> wrote: >> >>> On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore < >>> maurizio.cimadamore at oracle.com> wrote: >>> >>>> What I'm trying to say is that if a developer is confused (by the i++) >>>> on what "frozen" means for a loop variable, they won't find any clarity in >>>> our explanation that "lexically scoping trumps everything else". E.g. >>>> whether a developer reads the STEP part of a loop as part of the body >>>> (after the end of the body) or not is, I believe, a very subjective thing - >>>> and one which affects how any change we make in the area will be perceived >>>> (IMHO). >>>> >>> Yes, if a developer is mentally cutting and pasting the STEP onto the >>> tail of the BODY then you're right, that makes it appear as if the variable >>> is not really "frozen". >>> >>> But the original basic for() proposal has the analogous problem - i.e., >>> if a developer is mentally cutting and pasting the STEP onto the tail of >>> the BODY, then in the original proposal the variable no longer appears to >>> be "effectively final in the body of the loop". >>> >>> So it seems to me that this proposal and the original basic for() >>> proposal suffer equally in that particular respect, and such a developer is >>> not going to be satisfied by either of these new mental models. >>> >>>> Of course, as with every new proposed feature, we hear a lot from >>>> developers who think that the new proposal addresses a specific pain point >>>> that they thought should never existed in the first place. But we tend to >>>> hear less about a less vocal portion of users who might just be silently ok >>>> with the status quo. Or maybe, in this instance, we don't hear from them >>>> because they aren't there (although, Tagir expressed some concerns [1], so >>>> I have to assume there are such developers out there _somewhere_ :-) ) >>>> >>> I too would like to hear more opinions... speak up, naysayers :) >>> >>> -Archie >>> >>> -- >>> Archie L. Cobbs >>> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Tue Oct 22 01:12:59 2024 From: john.r.rose at oracle.com (John Rose) Date: Mon, 21 Oct 2024 18:12:59 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> Message-ID: <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> On 21 Oct 2024, at 10:00, Archie Cobbs wrote: > On Mon, Oct 21, 2024 at 11:36?AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> What I'm trying to say is that if a developer is confused (by the >> i++) on >> what "frozen" means for a loop variable, they won't find any clarity >> in our >> explanation that "lexically scoping trumps everything else". E.g. >> whether a >> developer reads the STEP part of a loop as part of the body (after >> the end >> of the body) or not is, I believe, a very subjective thing - and one >> which >> affects how any change we make in the area will be perceived (IMHO). >> > Yes, if a developer is mentally cutting and pasting the STEP onto the > tail > of the BODY then you're right, that makes it appear as if the variable > is > not really "frozen". > > But the original basic for() proposal has the analogous problem - > i.e., if > a developer is mentally cutting and pasting the STEP onto the tail of > the > BODY, then in the original proposal the variable no longer appears to > be > "effectively final in the body of the loop". > I think there might be something worth doing with some concept possibly denotable as ?effectively frozen?, so I read quickly through much of this thread but failed to find the definition of ?frozen? per se (that is, explicitly, not effectively, frozen). Lots of references with ?you-know-what-I-mean? quotes, but I can?t tell what ?frozen? is supposed to mean here. (I will thank anyone who points out the definition in this thread of ?frozen?. But I will plough forward with my own attempt?) The discussions of breaking the foundations of the language, making the same variable sometimes final and sometimes mutable, as control flows through different parts of loop syntax, do not impress me. Languages are usually grown by adding new constructs that desugar to known-good old constructs, not by destroying protective mechanisms that happen to get in the way. As with final, there MIGHT be concept of ?frozen? that is worth making ?effectively? present, but first we need to take a moment to define the non-effectively, EXPLICIT version. Even if we never ship it, which I think we won?t. Also, naming is hard. This discussion of ?frozen? is not the same as ?freezing? in other related areas of Java (JMM, ?frozen arrays? proposals). The problem at hand can only be solved (IMO) if you incorporate some sort of shadowing of the affected variables, so that the ?view? of the affected loop variable is selectively shadowed by a read-only duplicate of the loop variable, in the body of the for-loop. Let?s say that some variables (TBD), in some circumstances (TBD), can be subject to a special form of shadowing (JLS 6.4.1) called ?final shadowing?. If it went into the JLS, it would probably be mentioned in 6.4.1 along with all the other instances of shadowing. PSEUDO-SPEC: >> [In some circumstances] a local variable x may be final-shadowed on >> some statement S in part of its scope (JLS 6.3). When this is done, >> the effect is as if another declaration of the same name x is >> introduced, as a final local variable of the same type as the >> original declaration, which is initialized to the current value (as >> of S) of the original variable x. (Such a declaration could not be >> written explicitly, as it would is illegal to explicitly shadow a >> local by another local of the same name.) A final-shadowing >> declaration may only be introduced implicitly. In addition, it is >> only introduced for a statement S that performs no assignment to x. >> The scope of the shadowing final variable x is the statement S, only. And also I think we should nail down the use of this tactic: >> In addition final-shadowing is only done for a variable x declared by >> old-for loop, and for the body S of that same old-for loop. It is >> done whenever the >> body S contains a lambda that captures x. It is done in no other >> circumstances. Thus, the implicit introduction of final-shadowing may only happen when it has no effect on the behavior of the affected variable. Final-shadowing is thus largely transparent to the user, having no effect on occurrences of x in S. Occurrences of the name x before and/or after S are not shadowed. Within S, all occurrences of the name x are scoped to the final-shadowing declaration. The effect of final-shadowing a variable x in a statement S may be visualized as if S is rewritten to the block statement ?{final var x$1 = x; S$1;}? where x$1 is a new name not occurring in the program, and S$1 is simply S with all occurrences of x replaced by x$1. Having written all of this down, I realize that there is only a small motivation to make any of it explicit, as a user-specifiable syntax. (But it could be, something like ?final x;?) If the only point of final-shadowing is to enhance capture, we can have the discussion about where to apply the technique, but we don?t need to bikeshed a syntax, unless the user model requires explicitness in some way. The only place we urgently need such shadowing is to fix the problem with old-for loops and lambda-capture, so we can narrow the applicability to exactly variables x declared by a for-loop, and applied (when possible and useful) to the body of the for-loop. We could keep in our back pocket an option to invent a general and explicit syntax in the future, if for some reason we wanted to let users make explicit declarations of final shadowing at random points in their code. The only user-visible effect of final-shadowing is to enable lambda-capture (for x, in the statement S where it is final-shadowed). What?s so special about old-for loops? If final-shadowing is useful for old-for loops, why not do it everywhere a capture is attempted? Maybe in the future, but there are a number of issues to iron out, once you generalize beyond old-for loops. The special thing about loops (all kinds) is their bodies are executed N times, where N can be greater than one, for any single given execution of the containing statement or block. Any variable declared outside of the loop is declared once but might be used N times during the N executions of the loop body. This raises a special question of something like final-shadowing, for uses in the loop body. After all, you can mark a variable final, but such a variable cannot be given different values during those N executions, unless it is declared within the loop body itself. And the loop header is just outside the loop body. The extra-special thing about old-for loops is they can declare a variable x (or several) in their header. Such a variable has, arguably, an exactly bipartite scope. Typically (not always) the for-header has all the logic which steps the variable through a range of values, while the for-body operates (typically, not always) only on one value of that variable. I think the consensus (almost unanimous) is that something like the final-shadowing trick on the loop body would be a fine move, though not earth-shaking. It would make old-for and new-for be more like each other which is good. It would leave while loops out of the party, but? it?s a different keyword, and also you can refactor a while to be an old-for. What about while loops? What if I declare my iteration variables before my while loop? Why should I have to declare it in the old-for loop to get the extra help from final-shadowing? Why not apply the trick to all loop bodies of all kinds? That takes us to deeper waters. Doing this would allow a lambda to capture a loop-varying value. But some loops mutate the iteration variable in the loop, so what about the limitation that the value should not be modified by the loop body ? should we relax that? Along that slippery slope we quickly fall into the question of opening the floodgates, and doing final-shadowing on all lambdas everywhere. The rules for a stable spot (not just halfway sliding down the slope) are hard to foresee. Do we allow any statement anywhere to be (potentially) final-shadowed, if the language wishes it, in order to do lambda-capture? How close do we allow side effects to get to final-shadowed place? The simplest endpoint is just to go with so-called value-sampling lambdas (C++ has them), which don?t even pretend to capture the variable; they just internally do something like final-shadowing, capturing the present value of the up-level variable, giving it the same name, and allowing the lambda to work with that snapshot, even while the up-level variable continues to change. Why did?t we do this? There are number of reasons, but the core design goal for capture (of up-level variables in both lambdas and inner classes) was to eliminate the opportunity to observe a divergence in the behavior of the original up-level variable, as opposed to the name which represents it in the lambda. This is obviously a good goal, since code is easier to read when the same name means the same thing everywhere, as opposed to ?sometimes the live variable and sometimes a snapshot I already took?, which is what lambda snapshots give you. Note that fixing old-for loop cannot add much confusion of this sort, since the variable in question already has two clearly distinct zones of use, even though it has but one scope. Random variables outside of the loop, even if used in the loop, do not enjoy this clarity of usage. We certainly didn?t want to ?stretch? real JVM locals to somehow be simultaneously present in lambdas and their defining blocks. (In the ?90s we prototyped sharing a reference to a mutable box but that was a disaster in several ways.) Thus, the translation strategy needs to copy a value, for an efficient JVM implementation and race-free behavior. Still, we wanted to hide that copy, rather than make it be an artifact of the user experience. Hence, Java 1.1 says ?only capture finals? and Java 8 says ?and also effective finals?. (By the way, capturing a field does not copy. It copies the enclosing ?this? pointer, and so both the lambda and the original block ?see? the same variable, with all of its future mutations. The common thread here that, for both fields and final locals, a capture captures 100% of the future history of the variable, equally available to both parties.) The present suggestion of final-shadowing is really a tool for moderating that policy, by nailing down a mutable variable in specific places to behave ?final enough? to be captured. And after going over it, I think those places are exactly old-for loops, and nowhere else, at least not yet. Any other place beyond an old-for loop must either have an explicit marking (syntax TBD) or else be similarly as paradox-free as old-for loops. Here?s a paradox to avoid: ``` int x = 1; Supplier last = null; for (; x < 10; x++) { last = () -> x; } assert last.get() == x; //FAILS ``` The full history of x conflicts with the capture of x, and specifically the final post-loop value of x is surprising to the user of the lambda. The old-for loop variables do not have this opportunity for conflict. Here?s a more comprehensive example to examine, where the old-for loop makes ?one of each kind? of variable: ``` for (int i = 0, j = LIMIT, k = 0; i < j; i++) { foo(() -> bar(i)); // i: LEGAL AFTER FINAL-SHADOW foo(() -> bar(j)); // j: EFF-FINAL //foo(() -> bar(k)); // k: ALWAYS ILLEGAL k++; } ``` That might work, and might be enough to remove a serious rough edge from old-for loops. Beyond that, I don?t see any immediate wins. -------------- next part -------------- An HTML attachment was scrubbed... URL: From mark.reinhold at oracle.com Tue Oct 22 15:37:21 2024 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Tue, 22 Oct 2024 15:37:21 +0000 Subject: New candidate JEP: 494: Module Import Declarations (Second Preview) Message-ID: <20241022153719.21BC277EFDA@eggemoggin.niobe.net> https://openjdk.org/jeps/494 Summary: Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature. - Mark From mark.reinhold at oracle.com Tue Oct 22 15:37:24 2024 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Tue, 22 Oct 2024 15:37:24 +0000 Subject: New candidate JEP: 495: Simple Source Files and Instance Main Methods (Fourth Preview) Message-ID: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> https://openjdk.org/jeps/495 Summary: Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large. This is a preview language feature. - Mark From archie.cobbs at gmail.com Tue Oct 22 18:35:58 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 22 Oct 2024 13:35:58 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> Message-ID: On Mon, Oct 21, 2024 at 8:13?PM John Rose wrote: > I think there might be something worth doing with some concept possibly > denotable as ?effectively frozen?, so I read quickly through much of this > thread but failed to find the definition of ?frozen? per se (that is, > explicitly, not effectively, frozen). Lots of references with > ?you-know-what-I-mean? quotes, but I can?t tell what ?frozen? is supposed > to mean here. > > (I will thank anyone who points out the definition in this thread of > ?frozen?. But I will plough forward with my own attempt?) > My apologies for "effectively frozen", it was an off-the-cuff placeholder, but a poor one because as you point out "freezing" and "frozen" have their own (mostly unrelated) history. Anyway, here's the definition we were using... maybe a better term would be "quiescent"? Let v be a variable, and let P be a character position in a source file. Then *v is *quiescent* at P* if there exists no position Q ? P at which there exists an assignment to, or mutation of, v. Then a variable may be captured by a lambda at P only if it's quiescent at P. Note, locations Q ? P include the lambda itself so this enforces no mutations within the lambda. The thought was that "quiescent" might be a candidate pragmatic answer (read: compromise that satisfies no one :) as it's easy to understand and would permit most capturing scenarios while still avoiding the most acute form of the ambiguity that "effectively final" was designed to avoid. As a data point, this change would allow elimination of 94% of the "dummy variables" in the JDK itself. Re: "final shadowing - that is a nice concept - it aligns with the reality of what actually happens (usually a good thing). > Along that slippery slope we quickly fall into the question of opening the > floodgates, and doing final-shadowing on all lambdas everywhere.... > > Why did?t we do this? There are number of reasons, but the core design > goal for capture (of up-level variables in both lambdas and inner classes) > was to eliminate the opportunity to observe a divergence in the behavior of > the original up-level variable, as opposed to the name which represents it > in the lambda. > This made me realize this issue really is all just about naming. For example, outer instances are captured just like variables, but we don't have a problem there because the captured version of the variable has a different name inside the nested class vs. outside (i.e., "Outer.this" vs. "outer", if you create the nested class via "outer.new Inner()"). So with a captured variable, we are using the same name for what are in reality two different things. But instead of saying "these are really two different things" we say "there is only one possible value this/these things could have no matter where you are and so you can just pretend there is only one thing". > This is obviously a good goal, since code is easier to read when the same > name means the same thing everywhere, as opposed to ?sometimes the live > variable and sometimes a snapshot I already took?, which is what lambda > snapshots give you. > Entering personal opinion territory here... I wouldn't see such a big downside with allowing capture of any variable. Maybe that's just because I know how it really works? It's just a read-only snapshot taken at that point. Even if it were a new concept, that's just not a hard concept to grasp... especially in light of the many trickier Java topics like superclass constructors invoking subclass methods, mutual recursion between class initializers, anything to do with multi-threaded code... To me the "effectively final" requirement is like a baby gate that you have to step over every time you walk between the kitchen and the dining room. It's not a huge obstacle or anything, but it makes you wonder, who are the toddlers we are trying to protect here? And haven't they all grown up by now? :) Now back to practical reality... I've drafted a fix for basic for() loops & would be interested in your feedback. Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb9n at gmail.com Tue Oct 22 19:23:40 2024 From: kevinb9n at gmail.com (Kevin Bourrillion) Date: Tue, 22 Oct 2024 12:23:40 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> Message-ID: On Tue, Oct 22, 2024 at 11:37?AM Archie Cobbs wrote: > > This made me realize this issue really is all just about naming. For > example, outer instances are captured just like variables, but we don't > have a problem there because the captured version of the variable has a > different name inside the nested class vs. outside (i.e., "Outer.this" vs. > "outer", if you create the nested class via "outer.new Inner()"). > > So with a captured variable, we are using the same name for what are in > reality two different things. But instead of saying "these are really two > different things" we say "there is only one possible value this/these > things could have no matter where you are and so you can just pretend there > is only one thing". > sounds right to me. Entering personal opinion territory here... I wouldn't see such a big > downside with allowing capture of any variable. Maybe that's just because I > know how it really works? It's just a read-only snapshot taken at that > point. Even if it were a new concept, that's just not a hard concept to > grasp... especially in light of the many trickier Java topics like > superclass constructors invoking subclass methods, mutual recursion between > class initializers, anything to do with multi-threaded code... > I suspect it is specifically the fact that you can reference a field without `this.` and it really captures `this` that creates the problem here. Users would be regularly surprised that fields and locals don't work the same as each other. -------------- next part -------------- An HTML attachment was scrubbed... URL: From eirbjo at gmail.com Tue Oct 22 20:04:55 2024 From: eirbjo at gmail.com (=?UTF-8?B?RWlyaWsgQmrDuHJzbsO4cw==?=) Date: Tue, 22 Oct 2024 22:04:55 +0200 Subject: New candidate JEP: 495: Simple Source Files and Instance Main Methods (Fourth Preview) In-Reply-To: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> References: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> Message-ID: Hi! I love this feature! However, nothing is ever simple in programming. Especially for beginners. "Simple" is subjective, vague, generic and unquantifiable. "Simpler" would be more honest, but perhaps it would be possible to come up with something that actually describes this awesome feature? The JEP summary and goals sections have some bits to start with: "smoother on-ramp", "programming in the small", "beginner friendly". "reduced ceremony" "small programs". Cheers, Eirik. On Tue, Oct 22, 2024 at 5:38?PM Mark Reinhold wrote: > https://openjdk.org/jeps/495 > > Summary: Evolve the Java programming language so that beginners can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate > dialect of the language, beginners can write streamlined declarations > for single-class programs and then seamlessly expand their programs > to use more advanced features as their skills grow. Experienced > developers can likewise enjoy writing small programs succinctly, > without the need for constructs intended for programming in the large. > This is a preview language feature. > > - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Wed Oct 23 10:14:19 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 23 Oct 2024 11:14:19 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> Message-ID: <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> On 22/10/2024 19:35, Archie Cobbs wrote: > This made me realize this issue really is all just about naming. For > example, outer instances are captured just like variables, but we > don't have a problem there because the captured version of the > variable has a different name inside the nested class vs. outside > (i.e., "Outer.this" vs. "outer", if you create the nested class via > "outer.new Inner()"). I think this observation hits the nails on the head. When we capture ?fields? we don?t really capture mutable boxes, we capture an (immutable) reference to the enclosing class. I say immutable because the enclosing class reference is snapshotted, at construction - e.g. if you have: |Outer outer = new Outer(); // 1 Outer.Inner inner = outer.new Inner(); outer = new Outer(); // 2 | This is all legal code. One might wonder: does this code mean that Inner?s enclosing instance is updated in (2)? No, because, really, it?s as if the value of ?outer? was snapshotted when we created Inner, and a reference to that snapshotted value was saved. Since we access that snapshotted reference using |Outer.this| (and not |outer|), we sort of preserve the illusion that snapshotting doesn?t occur here - the class is accessing its ?enclosing instance? which is a separate thing from a ?field defined in the enclosing class?. So yes, a big part of this exercise is in trying to keep variable names meaning the same thing no matter where they appear (captured or not). If we start snapshotting everything, then you have two version of a local, the one snapshotted and captured e.g. inside a lambda, and the one (maybe mutable!) available outside. My subjective opinion here is that, if this principle is important (and, as John mentioned, it was very painfully front and center when inner classes were first added to the language), giving this principle up to allow capture in an extra 20-30 imperative loops (in an entire codebase) doesn?t look a great deal. That is, reducing asymmeties between counted loops and for-each loop comes at a price: now capture variables no longer mean the same thing they do in their non-captured context. Of course you can argue it both ways: by making the new capture treatment only available for induction variables in for loops (where the variable is not mutated in the body) we do reduce (not eliminate!) the chances of somebody observing different values for the same induction variable. Is that enough to put our minds at ease? Overall, it seems to me that this a very subjective topic: there is no well-defined principle as to why imperative for loops should behave any different than they do today, as there is (likely) no well-defined principle as to why for-each loop behaves the way it does today. How you "fix" this largely depends on (a) how you find this asymmetry annoying (which likely depends on exposure - and different code bases might have different levels of that) and (b) how much your developer intuition is trained to view the loop induction variable as a single mutable *variable*, or a series of *values* where each value is derived from the former in a controlled fashion. I don't have a strong (enough) opinion on either :-) Maurizio ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Wed Oct 23 12:00:23 2024 From: ron.pressler at oracle.com (Ron Pressler) Date: Wed, 23 Oct 2024 12:00:23 +0000 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> Message-ID: > On 23 Oct 2024, at 11:14, Maurizio Cimadamore wrote: > > My subjective opinion here is that, if this principle is important (and, as John mentioned, it was very painfully front and center when inner classes were first added to the language), giving this principle up to allow capture in an extra 20-30 imperative loops (in an entire codebase) doesn?t look a great deal. That is, reducing asymmeties between counted loops and for-each loop comes at a price: now capture variables no longer mean the same thing they do in their non-captured context. I think this is a matter of perspective. Suppose you have: for (int x : List.of(0, 1, 2)) { ? } and for (int x = 0; x < 3; x++) { ? } In both situations, the capture would fail if we reassign x inside the loop?s body (whether inside the lambda or outside it), and in both situations `x` will be bound to different values over time inside the loop?s body but outside the lambda, but not inside it, where it is snapshotted (assuming it is kept somewhere and evaluated after some time). That x really means something subtly different in the foreach loop and the classic loop is more of an implementation detail. I don?t know the history of that choice, and it did predate lambda, but if it was made to allow a final index to be captured in an index class, then capturability is the motivation for that detail. ? Ron From maurizio.cimadamore at oracle.com Wed Oct 23 13:52:55 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 23 Oct 2024 14:52:55 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> Message-ID: On 23/10/2024 13:00, Ron Pressler wrote: > That x really means something subtly different in the foreach loop and > the classic loop is more of an implementation detail. I don?t know the > history of that choice, and it did predate lambda, but if it was made to > allow a final index to be captured in an index class, then > capturability is the motivation for that detail. I don't disagree that is a matter of perspective (I called it subjective). As I stated: > How you "fix" this largely depends on (a) how you find this asymmetry > annoying (which likely depends on exposure - and different code bases > might have different levels of that) and (b) how much your developer > intuition is trained to view the loop induction variable as a single > mutable *variable*, or a series of *values* where each value is > derived from the former in a controlled fashion. I don't have a strong > (enough) opinion on either :-) IMHO both (a) and (b) are subjective calls. I feel that some developers will stand by the asymmetry because for-each is special, and doesn't use mutation (no need to do `i++`) so _of course_ you get a "fresh" `i` on a for-each iteration (but not in an imperative for loop). This is further reinforced by the fact that you can add `final` on for-each variables, but not in the imperative loop induction variables. Other developers will find this distinction annoying, because in a well-behaved counted loop, the mutation of the induction variable is so controlled that it can largely be ignored (and be treated as an impl detail). I think both views have their own merits Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Oct 23 15:26:02 2024 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 23 Oct 2024 11:26:02 -0400 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> Message-ID: As usual, everybody's right :) I think Ron has captured the stewardship argument about how we would like users to view the language: that the two sorts of loops, assuming each are "well behaved", should be interchangeable, refactorable to each other, etc, and that the differences in scoping should be an "implementation detail." And Maurizio is correct that people have formed their own mental models about how both kinds of loops work, and for some, changing them will be "fixing a bug", and for others, it will be taking something straightforward (x++ in the loop header is straight mutation, nothing to see here) and distorting it. Given that we have the language we have, what to do here is mostly based on a cost-benefit analysis where both the costs and benefits are subjective.? And, I think it's kind of close; I think there's a simple thing we could do here that would be a net improvement, but we could also justify (as we did in 8) doing nothing special here. Honestly, I think both kinds of loops are weak; the "legacy C" loops suffer mightily from having copied too literally (and yet poorly) from C, with the result being that they are both too general for the average case and too weak for the general case. The foreach loops suffers from the (explicit) desire to capture the 90/10 point.? The result being that they both have irritating sharp edges that make you want to refactor from one to the other, and sometimes back.? Which makes gratuitous asymmetries in how they interact with other features (scoping and capture) even more irritating, because one forced refactoring will then force another refactoring. On 10/23/2024 9:52 AM, Maurizio Cimadamore wrote: > > > On 23/10/2024 13:00, Ron Pressler wrote: >> That x really means something subtly different in the foreach loop and >> the classic loop is more of an implementation detail. I don?t know the >> history of that choice, and it did predate lambda, but if it was made to >> allow a final index to be captured in an index class, then >> capturability is the motivation for that detail. > > I don't disagree that is a matter of perspective (I called it > subjective). As I stated: > >> How you "fix" this largely depends on (a) how you find this asymmetry >> annoying (which likely depends on exposure - and different code bases >> might have different levels of that) and (b) how much your developer >> intuition is trained to view the loop induction variable as a single >> mutable *variable*, or a series of *values* where each value is >> derived from the former in a controlled fashion. I don't have a >> strong (enough) opinion on either :-) > > IMHO both (a) and (b) are subjective calls. I feel that some > developers will stand by the asymmetry because for-each is special, > and doesn't use mutation (no need to do `i++`) so _of course_ you get > a "fresh" `i` on a for-each iteration (but not in an imperative for > loop). This is further reinforced by the fact that you can add `final` > on for-each variables, but not in the imperative loop induction variables. > > Other developers will find this distinction annoying, because in a > well-behaved counted loop, the mutation of the induction variable is > so controlled that it can largely be ignored (and be treated as an > impl detail). > > I think both views have their own merits > > Maurizio > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Wed Oct 23 19:28:27 2024 From: john.r.rose at oracle.com (John Rose) Date: Wed, 23 Oct 2024 12:28:27 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> Message-ID: <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> On 23 Oct 2024, at 3:14, Maurizio Cimadamore wrote: > ? > So yes, a big part of this exercise is in trying to keep variable names meaning the same thing no matter where they appear (captured or not). If we start snapshotting everything, then you have two version of a local, the one snapshotted and captured e.g. inside a lambda, and the one (maybe mutable!) available outside. Good summary. > ? > Of course you can argue it both ways: by making the new capture treatment only available for induction variables in for loops (where the variable is not mutated in the body) we do reduce (not eliminate!) the chances of somebody observing different values for the same induction variable. I don?t see the sub-point about ?not eliminate?; I think the reduction is complete to the point of elimination, because of the special (weird) properties of the old-for loop. For me the unique justification of final-shadowing a variable (1) declared by the old-for loop and (2) exactly in the body of the loop means that ?somebody can observe? variations in the value of that variable exactly and only in the old-for loop header. That fulfills the goal of fully eliminating chances for somebody seeing unexpected values. With the admitted exception of the old-for loop header, but that is exactly where everybody EXPECTS to see such variations. So the chance of surprise is (uniquely) low for this (very particular) case. That?s why I think we should use apply the (helpful? interesting?) idea of final-shadowing exactly in this one circumstance where it will cause very much more benefit than surprise. (Do we use final-shadowing again? Maybe not, but for me it is a clarifying concept.) I also think the feature will be enjoyed far more than ?20 or 30? times, or whatever corpus analysis tells us. Corpus analysis by definition measures the way people have used the language in the past, and that is often affected by their avoidance of sharp corners in the language. I believe this little polish of a central syntax in Java will affect the way people shape their code in the future. At least, it will for me, because I know I?ve done extra work to avoid the sharp corner in the past. ? John P.S. Archie, I don?t think character positions should be appealed to; that?s not a natural tactic for the JLS. (Despite some very low-level and odd rules about forward references between field initializers, which sort of depend on character positions.) Appealing to character positions instead of block structure inhibits understanding of code at the AST level (which IDEs want to do). If I were going in that direction I?d piggy-back on the reachability analysis the JLS already has, in order to track setting of finals. I?d ask, ?can the captured variable be reassigned in some code B reachable from the capture point A?? in a way analogous to asking ?can this final, once assigned at point A, ever be reassigned at point B?? Note the connection to finals, which is not accidental. Finals are all about saying, ?this variable is only a value, and does not provide access to a future evolution of states?. From maurizio.cimadamore at oracle.com Wed Oct 23 20:55:20 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 23 Oct 2024 21:55:20 +0100 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> Message-ID: <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> >> ? >> Of course you can argue it both ways: by making the new capture treatment only available for induction variables in for loops (where the variable is not mutated in the body) we do reduce (not eliminate!) the chances of somebody observing different values for the same induction variable. > I don?t see the sub-point about ?not eliminate?; I think the reduction is complete to the point of elimination, because of the special (weird) properties of the old-for loop. Well, there's no sub-point - I'm merely stating the (perhaos obvious?) fact that if you allow to capture induction variable you can set up a contrived example where you execute a lambda which captures the _previous_ version of the induction variable. That said, the same thing happens in for-each loops - so we're back to the subjective judgment of whether it's ok for counted loop to have same rules of for-each loops despite a more explicit mutation (even if controlled). > I also think the feature will be enjoyed far more than ?20 or 30? times, or whatever corpus analysis tells us. Corpus analysis by definition measures the way people have used the language in the past, and that is often affected by their avoidance of sharp corners in the language. I believe this little polish of a central syntax in Java will affect the way people shape their code in the future. At least, it will for me, because I know I?ve done extra work to avoid the sharp corner in the past. Here I don't think I agree. It's not like developers are avoiding loop because the capture rules are what they are. If you need a loop, you need a loop. Maybe they are avoiding capturing lambdas - but again, replaced with what? Anonymous inner classes will have similar issues. And if you need capture you need capture - you can't make that go away. Perhaps they are disguising the capture a little harder, by using an array, or an AtomicXYZ. But I'd say that, while the numbers we have seen might surely underestimate things a bit, I don't expect to see dramatic differences in the wild. There's another reason I think this is the case - since Java 8 there are often better ways to write loops: using the Stream API. Of course not every loop can be rewritten using streams, but a lot can, and developers have already done so - perhaps lowering the number of legacy loops (of all kinds) requiring some kind of capture. Maurizio > > ? John > > P.S. Archie, I don?t think character positions should be appealed to; that?s not a natural tactic for the JLS. (Despite some very low-level and odd rules about forward references between field initializers, which sort of depend on character positions.) Appealing to character positions instead of block structure inhibits understanding of code at the AST level (which IDEs want to do). If I were going in that direction I?d piggy-back on the reachability analysis the JLS already has, in order to track setting of finals. I?d ask, ?can the captured variable be reassigned in some code B reachable from the capture point A?? in a way analogous to asking ?can this final, once assigned at point A, ever be reassigned at point B?? Note the connection to finals, which is not accidental. Finals are all about saying, ?this variable is only a value, and does not provide access to a future evolution of states?. -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Wed Oct 23 21:49:04 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 23 Oct 2024 23:49:04 +0200 (CEST) Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> References: <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> Message-ID: <1292764959.27223.1729720144243.JavaMail.zimbra@univ-eiffel.fr> > From: "Maurizio Cimadamore" > To: "John Rose" > Cc: "Archie Cobbs" , "amber-dev" > , "Liam Miller-Cushon" > Sent: Wednesday, October 23, 2024 10:55:20 PM > Subject: Re: JDK-8300691 - final variables in for loop headers should accept > updates >>> ? >>> Of course you can argue it both ways: by making the new capture treatment only >>> available for induction variables in for loops (where the variable is not >>> mutated in the body) we do reduce (not eliminate!) the chances of somebody >>> observing different values for the same induction variable. >> I don?t see the sub-point about ?not eliminate?; I think the reduction is >> complete to the point of elimination, because of the special (weird) properties >> of the old-for loop. > Well, there's no sub-point - I'm merely stating the (perhaos obvious?) fact that > if you allow to capture induction variable you can set up a contrived example > where you execute a lambda which captures the _previous_ version of the > induction variable. That said, the same thing happens in for-each loops - so > we're back to the subjective judgment of whether it's ok for counted loop to > have same rules of for-each loops despite a more explicit mutation (even if > controlled). >> I also think the feature will be enjoyed far more than ?20 or 30? times, or >> whatever corpus analysis tells us. Corpus analysis by definition measures the >> way people have used the language in the past, and that is often affected by >> their avoidance of sharp corners in the language. I believe this little polish >> of a central syntax in Java will affect the way people shape their code in the >> future. At least, it will for me, because I know I?ve done extra work to avoid >> the sharp corner in the past. > Here I don't think I agree. It's not like developers are avoiding loop because > the capture rules are what they are. If you need a loop, you need a loop. Maybe > they are avoiding capturing lambdas - but again, replaced with what? Anonymous > inner classes will have similar issues. And if you need capture you need > capture - you can't make that go away. Perhaps they are disguising the capture > a little harder, by using an array, or an AtomicXYZ. But I'd say that, while > the numbers we have seen might surely underestimate things a bit, I don't > expect to see dramatic differences in the wild. > There's another reason I think this is the case - since Java 8 there are often > better ways to write loops: using the Stream API. Of course not every loop can > be rewritten using streams, but a lot can, and developers have already done so > - perhaps lowering the number of legacy loops (of all kinds) requiring some > kind of capture. As a teacher, here is the issue most of my student struggle with, they have a code like for(var i = 0; i < 4; i++) { new Thread(() -> { ... }).start(), } The code can use plain threads, virtual threads, an executor or structured concurrency, etc ... you get the idea. Then they want to access to induction variable 'i' inside the lambda. At that point, some students knows how to fix the issue using another local variable in the body of the loop but others start to become "creative", - some are using IntStream.range().forEach(i -> ) but usually, it fails because it's quite usual for this kind of code to have also a method call that throws a checked exception (Thread.sleep(), object.wait(), thread.join(), future.get(), etc) - some try to write their own range() method using an "enhanced for" like Tagir said, here are the usual examples - for(var i : List.of(0, 1, 2, 3)) { - for(var i : IntStream.range(0, 4).boxed().toList()) { - for(var i : new int[] { 0, 1, 2, 3 }) { - for(var i : (Iterable) IntStream.range(0, 4)::iterator) { // those students have read Effective Java For me, allowing my students to capture the induction variable of simple for loops so they can focus on the rest of the code is a win. > Maurizio R?mi >> ? John >> P.S. Archie, I don?t think character positions should be appealed to; that?s not >> a natural tactic for the JLS. (Despite some very low-level and odd rules about >> forward references between field initializers, which sort of depend on >> character positions.) Appealing to character positions instead of block >> structure inhibits understanding of code at the AST level (which IDEs want to >> do). If I were going in that direction I?d piggy-back on the reachability >> analysis the JLS already has, in order to track setting of finals. I?d ask, >> ?can the captured variable be reassigned in some code B reachable from the >> capture point A?? in a way analogous to asking ?can this final, once assigned >> at point A, ever be reassigned at point B?? Note the connection to finals, >> which is not accidental. Finals are all about saying, ?this variable is only a >> value, and does not provide access to a future evolution of states?. -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb9n at gmail.com Wed Oct 23 23:14:43 2024 From: kevinb9n at gmail.com (Kevin Bourrillion) Date: Wed, 23 Oct 2024 16:14:43 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <1292764959.27223.1729720144243.JavaMail.zimbra@univ-eiffel.fr> References: <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> <1292764959.27223.1729720144243.JavaMail.zimbra@univ-eiffel.fr> Message-ID: On Wed, Oct 23, 2024 at 3:53?PM Remi Forax wrote: > > - for(var i : List.of(0, 1, 2, 3)) { > - for(var i : IntStream.range(0, 4).boxed().toList()) { > - for(var i : new int[] { 0, 1, 2, 3 }) { > - for(var i : (Iterable) IntStream.range(0, 4)::iterator) { > // those students have read Effective Java > You've really seen students come up with all of these on their own? I mean, I credit your students for exploring and trying things, but these cures are all self-evidently worse than the disease. Hopefully the students are able to see that they're better off reverting to the "dumb" extra variable in this case. Then they've learned a useful lesson. To whatever extent users *really are* feeling compelled to go to such heroics to avoid this temporary variable, it says something about how viscerally "wrong" the variable feels. Clearly it's producing a "well this *can't be right*, I'd better keep looking for another way" intuition in people. I suppose that does constitute an argument in favor of the proposal, but I don't know how it should be weighted. But it would not be reasonable to compare the proposal against the four things above, and award it points for being better than *those* things, because they are *already* not the right solutions for the problem. -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Thu Oct 24 00:21:08 2024 From: john.r.rose at oracle.com (John Rose) Date: Wed, 23 Oct 2024 17:21:08 -0700 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <1292764959.27223.1729720144243.JavaMail.zimbra@univ-eiffel.fr> References: <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> <1292764959.27223.1729720144243.JavaMail.zimbra@univ-eiffel.fr> Message-ID: On 23 Oct 2024, at 14:49, Remi Forax wrote: >> > As a teacher, here is the issue most of my student struggle with, they have a code like > > for(var i = 0; i < 4; i++) { > new Thread(() -> { > ... > }).start(), > } > > The code can use plain threads, virtual threads, an executor or structured concurrency, etc ... you get the idea. > > Then they want to access to induction variable 'i' inside the lambda. > > At that point, some students knows how to fix the issue using another local variable in the body of the loop but others start to become "creative", > - some are using IntStream.range().forEach(i -> ) but usually, it fails because it's quite usual for this kind of code to have also a method call that throws a checked exception (Thread.sleep(), object.wait(), thread.join(), future.get(), etc) > - some try to write their own range() method using an "enhanced for" like Tagir said, here are the usual examples > - for(var i : List.of(0, 1, 2, 3)) { > - for(var i : IntStream.range(0, 4).boxed().toList()) { > - for(var i : new int[] { 0, 1, 2, 3 }) { > - for(var i : (Iterable) IntStream.range(0, 4)::iterator) { // those students have read Effective Java Wow. Each of those is personally familiar to me as well, as I tried to force new-for into a mold that was just slightly the wrong shape. While old-for has the right shape for this, according to long custom. Yuck. It reminds me of the story that ends ?with all this manure there?s got to be a pony in here somewhere?. Let?s give the kid his pony. > For me, allowing my students to capture the induction variable of simple for loops so they can focus on the rest of the code is a win. Yes. It could happen every time a learner sets out to make N threads, each doing something for some i References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> <02437772-e867-46b6-93d0-0e37beb7cd0b@oracle.com> Message-ID: Hi, here are my two cents after following the discussions. I personally find the limitation a little bit annoying. In my experience, most other languages (JS, Python, C++, Rust, ...) allow to capture (non-final) variables in lambdas. At least Java is the only language where I have noticed this limitation so far. However, I also don't find this limitation too bothersome. > I think Ron has captured the stewardship argument about how we would > like users to view the language: that the two sorts of loops, assuming > each are "well behaved", should be interchangeable, refactorable to > each other, etc, and that the differences in scoping should be an > "implementation detail." I think it is hard to explain that we may consider the variable of an old-style for-loop to be scoped to the individual iteration. Consider the behavior of the following code: for (int i = 0; i < 4; i++) { if (...) { i += 1; } } Changes on the variable made inside the body will affect future iterations. In other words, you would than need to explain that actually, the scope of the variable depends on whether the variable is modified within the body. I think you are better off just explaining that there is a special case implemented for allowing capturing variables of old-style for-loops. >> I also think the feature will be enjoyed far more than ?20 or 30? times, or whatever corpus analysis tells us. Corpus analysis by definition measures the way people have used the language in the past, and that is often affected by their avoidance of sharp corners in the language. I believe this little polish of a central syntax in Java will affect the way people shape their code in the future. At least, it will for me, because I know I?ve done extra work to avoid the sharp corner in the past. > > Here I don't think I agree. It's not like developers are avoiding loop > because the capture rules are what they are. If you need a loop, you > need a loop. Maybe they are avoiding capturing lambdas - but again, > replaced with what? Anonymous inner classes will have similar issues. > And if you need capture you need capture - you can't make that go > away. Perhaps they are disguising the capture a little harder, by > using an array, or an AtomicXYZ. But I'd say that, while the numbers > we have seen might surely underestimate things a bit, I don't expect > to see dramatic differences in the wild. > I would estimate that in 80 % of cases where I encountered the limitation, I ended up to refactor the code by either introducing an Iterable, so that I can use an enhanced for-loop, by extracting the content of the loop into a separate method, or by replacing the lambda with a named class. However, I think in a noticeable amount of cases, the code also got more readable after spending the additional time. At the end, I find the proposal which is special-cased to the for-loop a bit strange. While I wouldn't have a problem with it, I think it would always stay a feature specifically implemented for this style of loops. I don't think that you can explain it away. Also, as it has been shown earlier in the discussion, this solution would elevate the pain for not even half of the affected cases. I think that Java should remove the limitation in even more cases (as was proposed earlier), or focus on making enhanced for-loops more usable (for example by providing ranges). Note that in my experience, many languages (e.g. the same as mentioned at the start of this email) seem to put much more focus on making the enhanced for-loop the default. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Thu Oct 24 14:35:25 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 24 Oct 2024 14:35:25 +0000 Subject: New candidate JEP: 495: Simple Source Files and Instance Main Methods (Fourth Preview) In-Reply-To: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> References: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> Message-ID: <9F3736DC-8E65-4FE3-A446-877A9F7D2CAA@oracle.com> Dear experts: The first draft of a spec covering JEP 495: Simple Source Files and Instance Main Methods is available: https://cr.openjdk.org/~gbierman/jep495/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin On 22 Oct 2024, at 16:37, Mark Reinhold wrote: https://openjdk.org/jeps/495 Summary: Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Thu Oct 24 14:37:15 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 24 Oct 2024 14:37:15 +0000 Subject: New candidate JEP: 494: Module Import Declarations (Second Preview) In-Reply-To: <20241022153719.21BC277EFDA@eggemoggin.niobe.net> References: <20241022153719.21BC277EFDA@eggemoggin.niobe.net> Message-ID: Dear experts: The first draft of a spec covering JEP 494: Module Import Declarations is available: https://cr.openjdk.org/~gbierman/jep494/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin On 22 Oct 2024, at 16:37, Mark Reinhold wrote: https://openjdk.org/jeps/494 Summary: Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Thu Oct 24 14:50:20 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 24 Oct 2024 14:50:20 +0000 Subject: New candidate JEP: 495: Simple Source Files and Instance Main Methods (Fourth Preview) In-Reply-To: References: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> Message-ID: Point taken but the title reflects the language feature(s) being added. At the moment, according to the JLS (7.3), a *compilation unit* is the top-level symbol for Java programs in the grammar. A compilation unit can be ?ordinary? (containing a top level class or interface) or ?modular? (containing a module declaration). What this JEP is proposing is a new sort of compilation unit. In the draft spec we call this a ?simple" compilation unit, to contrast with ?ordinary?. As no human says the phrase ?compilation unit?, but rather everyone informally speaks of ?source files?, we ended up calling these new sorts of source files ?simple?. I guess one could say ?smoother on-ramp?, or any of the alternatives, was similarly ?...subjective, vague, generic and unquantifiable?. It?s hard but in the end we settled on using the two significant features (new sort of source file, new sort of main method) as the title. It?s a mouthful, but hopefully the community can help people interested in ?the on-ramp stuff I heard about? navigate to the right JEP. Hope this helps, Thanks, Gavin On 22 Oct 2024, at 21:04, Eirik Bj?rsn?s wrote: Hi! I love this feature! However, nothing is ever simple in programming. Especially for beginners. "Simple" is subjective, vague, generic and unquantifiable. "Simpler" would be more honest, but perhaps it would be possible to come up with something that actually describes this awesome feature? The JEP summary and goals sections have some bits to start with: "smoother on-ramp", "programming in the small", "beginner friendly". "reduced ceremony" "small programs". Cheers, Eirik. On Tue, Oct 22, 2024 at 5:38?PM Mark Reinhold > wrote: https://openjdk.org/jeps/495 Summary: Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Fri Oct 25 05:50:42 2024 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 25 Oct 2024 07:50:42 +0200 (CEST) Subject: New candidate JEP: 495: Simple Source Files and Instance Main Methods (Fourth Preview) In-Reply-To: References: <20241022153723.5B59777EFDC@eggemoggin.niobe.net> Message-ID: <566369298.1007762.1729835442111.JavaMail.zimbra@univ-eiffel.fr> > From: "Gavin Bierman" > To: "Eirik Bj?rsn?s" > Cc: "amber-dev" > Sent: Thursday, October 24, 2024 4:50:20 PM > Subject: Re: New candidate JEP: 495: Simple Source Files and Instance Main > Methods (Fourth Preview) Hello Gavin, > Point taken but the title reflects the language feature(s) being added. At the > moment, according to the JLS (7.3), a *compilation unit* is the top-level > symbol for Java programs in the grammar. A compilation unit can be ?ordinary? > (containing a top level class or interface) or ?modular? (containing a module > declaration). What this JEP is proposing is a new sort of compilation unit. In > the draft spec we call this a ?simple" compilation unit, to contrast with > ?ordinary?. As no human says the phrase ?compilation unit?, but rather everyone > informally speaks of ?source files?, we ended up calling these new sorts of > source files ?simple?. > I guess one could say ?smoother on-ramp?, or any of the alternatives, was > similarly ?...subjective, vague, generic and unquantifiable?. It?s hard but in > the end we settled on using the two significant features (new sort of source > file, new sort of main method) as the title. It?s a mouthful, but hopefully the > community can help people interested in ?the on-ramp stuff I heard about? > navigate to the right JEP. Reading the JLS changes, i also think that "simple" is not the best term, what about "primary compilation unit", the one you use before moving to an ordinary compilation unit ? > Hope this helps, > Thanks, > Gavin regards, R?mi >> On 22 Oct 2024, at 21:04, Eirik Bj?rsn?s wrote: >> Hi! >> I love this feature! However, nothing is ever simple in programming. Especially >> for beginners. >> "Simple" is subjective, vague, generic and unquantifiable. "Simpler" would be >> more honest, but perhaps it would be possible to come up with something that >> actually describes this awesome feature? >> The JEP summary and goals sections have some bits to start with: "smoother >> on-ramp", "programming in the small", "beginner friendly". "reduced ceremony" >> "small programs". >> Cheers, >> Eirik. >> On Tue, Oct 22, 2024 at 5:38 PM Mark Reinhold < [ >> mailto:mark.reinhold at oracle.com | mark.reinhold at oracle.com ] > wrote: >>> [ https://openjdk.org/jeps/495 | https://openjdk.org/jeps/495 ] >>> Summary: Evolve the Java programming language so that beginners can >>> write their first programs without needing to understand language >>> features designed for large programs. Far from using a separate >>> dialect of the language, beginners can write streamlined declarations >>> for single-class programs and then seamlessly expand their programs >>> to use more advanced features as their skills grow. Experienced >>> developers can likewise enjoy writing small programs succinctly, >>> without the need for constructs intended for programming in the large. >>> This is a preview language feature. >>> - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From angelos.bimpoudis at oracle.com Fri Oct 25 14:51:00 2024 From: angelos.bimpoudis at oracle.com (Angelos Bimpoudis) Date: Fri, 25 Oct 2024 14:51:00 +0000 Subject: New candidate JEP: 488: Primitive Types in Patterns, instanceof, and switch (Second Preview) In-Reply-To: <20240930200335.1ECAC77CADA@eggemoggin.niobe.net> References: <20240930200335.1ECAC77CADA@eggemoggin.niobe.net> Message-ID: Dear experts: The first draft of the spec covering JEP 488: Primitive Types in Patterns, instanceof, and switch (Second Preview) is available: https://cr.openjdk.org/~abimpoudis/instanceof/jep488-20241014/specs/primitive-types-in-patterns-instanceof-switch-jls.html (also https://cr.openjdk.org/~abimpoudis/instanceof/latest/) Feel free to contact me directly or on this list with any comments. Thanks Angelos ________________________________ From: Mark Reinhold Sent: 30 September 2024 22:03 To: Angelos Bimpoudis Cc: amber-dev at openjdk.org ; jdk-dev at openjdk.org Subject: New candidate JEP: 488: Primitive Types in Patterns, instanceof, and switch (Second Preview) https://openjdk.org/jeps/488 Summary: Enhance pattern matching by allowing primitive types in all pattern contexts, and extend instanceof and switch to work with all primitive types. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Fri Oct 25 15:02:20 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Fri, 25 Oct 2024 10:02:20 -0500 Subject: JDK-8300691 - final variables in for loop headers should accept updates In-Reply-To: <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> References: <83a9fa5b-69c1-47cd-bf2a-c49f16cda89f@oracle.com> <7c968acb-6db7-4a87-8b26-93f4f72050bf@oracle.com> <448f92ea-b103-4292-ae70-081ef71b3465@oracle.com> <507dbbe7-94d3-4dd6-8a13-afecbe599271@oracle.com> <094AF589-9E12-4F46-B512-BEEC3135380A@oracle.com> <9488f6b8-95a8-4d4a-bf54-757297eaff96@oracle.com> <3ACF4EBB-F749-4887-B005-7EA20A355099@oracle.com> Message-ID: On Wed, Oct 23, 2024 at 2:28?PM John Rose wrote: > That?s why I think we should use apply the (helpful? interesting?) idea of > final-shadowing exactly in this one circumstance where it will cause very > much more benefit than surprise. (Do we use final-shadowing again? Maybe > not, but for me it is a clarifying concept.) > I like the "final shadowing" concept... at least the name seems to accurately reflect what it is. > P.S. Archie, I don?t think character positions should be appealed to; > that?s not a natural tactic for the JLS. I agree that the definition of "quiescent" is contrived, though it does end up with an interesting/nice outcome... maybe that's just two wrongs making a right (the other "wrong" being the mismatch between the lexical and logical structure of the basic for() statement). Is there some quasi-consensus to go forward with this idea for fixing basic for() loops? I'm not the final judge on that, but if so I'm happy to contribute any further grunt work when needed. In any case, this has been an interesting discussion. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: