From pm at goldmensch.dev Tue Jul 8 03:30:35 2025 From: pm at goldmensch.dev (Goldmensch) Date: Tue, 08 Jul 2025 03:30:35 +0000 Subject: Locally enabled preview features Message-ID: Hi folks! I?m wondering if the idea of ?locally? enabled preview features came up yet. It would make it possible to enable certain preview features for a class, package or module by annotating it for example. Doing so would allow to use preview features much easier in production to test them, while keeping the usage ?scope? small so that changes can be easily integrated without risking the integrity of the codebase. Of course some feature like virtual threads (by the time they were in preview) could not be enabled in such way due to the consequences to ?non preview enabled code? but flexible constructor bodies, module import declarations, perhaps even scoped values and much more could be. Was this idea ever considered yet and if yes, what are the points against it? Best regards, Nick Hensel -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Jul 8 09:05:55 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 8 Jul 2025 11:05:55 +0200 (CEST) Subject: Locally enabled preview features In-Reply-To: References: Message-ID: <1353378114.37870818.1751965555884.JavaMail.zimbra@univ-eiffel.fr> > From: "Goldmensch" > To: "amber-dev" > Sent: Tuesday, July 8, 2025 5:30:35 AM > Subject: Locally enabled preview features > Hi folks! > I?m wondering if the idea of ?locally? enabled preview features came up yet. It > would make it possible to enable certain preview features for a class, package > or module by annotating it for example. Doing so would allow to use preview > features much easier in production to test them, while keeping the usage > ?scope? small so that changes can be easily integrated without risking the > integrity of the codebase. Of course some feature like virtual threads (by the > time they were in preview) could not be enabled in such way due to the > consequences to ?non preview enabled code? but flexible constructor bodies, > module import declarations, perhaps even scoped values and much more could be. > Was this idea ever considered yet and if yes, what are the points against it? It was considered and rejected. The preview mechanism has to be rough / raw, so it conveys the fact that there is no guarantee of backward compatibility from a release to the next one. Also, the implementation of a feature may change from one version to the next, a feature can be implemented as only a javac change in one version and as a bytecode change in the next version, so the notion of "scope" of a feature does not really exist. > Best regards, > Nick Hensel regards, R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Tue Jul 8 11:47:51 2025 From: davidalayachew at gmail.com (David Alayachew) Date: Tue, 8 Jul 2025 07:47:51 -0400 Subject: Locally enabled preview features In-Reply-To: <1353378114.37870818.1751965555884.JavaMail.zimbra@univ-eiffel.fr> References: <1353378114.37870818.1751965555884.JavaMail.zimbra@univ-eiffel.fr> Message-ID: To add onto that, having the option as a commandline makes it 100% unavoidable for the person running the code to know that they are running preview code. That's the entire point of making it a CLI option vs an annotation -- so that the person running the code can be made aware of the risk. On Tue, Jul 8, 2025, 5:06?AM Remi Forax wrote: > > > ------------------------------ > > *From: *"Goldmensch" > *To: *"amber-dev" > *Sent: *Tuesday, July 8, 2025 5:30:35 AM > *Subject: *Locally enabled preview features > > Hi folks! > I?m wondering if the idea of ?locally? enabled preview features came up > yet. It would make it possible to enable certain preview features for a > class, package or module by annotating it for example. Doing so would allow > to use preview features much easier in production to test them, while > keeping the usage ?scope? small so that changes can be easily integrated > without risking the integrity of the codebase. Of course some feature like > virtual threads (by the time they were in preview) could not be enabled in > such way due to the consequences to ?non preview enabled code? but flexible > constructor bodies, module import declarations, perhaps even scoped values > and much more could be. > > Was this idea ever considered yet and if yes, what are the points against > it? > > > It was considered and rejected. > > The preview mechanism has to be rough / raw, so it conveys the fact that > there is no guarantee of backward compatibility from a release to the next > one. > > Also, the implementation of a feature may change from one version to the > next, a feature can be implemented as only a javac change in one version > and as a bytecode change in the next version, so the notion of "scope" of a > feature does not really exist. > > > Best regards, > Nick Hensel > > > regards, > R?mi > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From chen.l.liang at oracle.com Tue Jul 8 14:03:58 2025 From: chen.l.liang at oracle.com (Chen Liang) Date: Tue, 8 Jul 2025 14:03:58 +0000 Subject: Locally enabled preview features In-Reply-To: References: Message-ID: I think there are something related to your problem - the multi-release jars do attempt to increase integration with different feature sets, and in fact, JLS requires class files that is compiled with --enable-preview but did not make use of any preview features to have their minor version set to 0. So to control the scope, I think either using multiple compilation (multiple source sets) or checking the minor version in class files to determine the scope works. As to your proposal - you see others have already listed a few arguments against it, and it is not the only way to address your problem. I hope the two existing solutions I listed above can somewhat alleviate the problem you face. Regards, Chen ________________________________ From: amber-dev on behalf of Goldmensch Sent: Monday, July 7, 2025 10:30 PM To: amber-dev at openjdk.org Subject: Locally enabled preview features Hi folks! I?m wondering if the idea of ?locally? enabled preview features came up yet. It would make it possible to enable certain preview features for a class, package or module by annotating it for example. Doing so would allow to use preview features much easier in production to test them, while keeping the usage ?scope? small so that changes can be easily integrated without risking the integrity of the codebase. Of course some feature like virtual threads (by the time they were in preview) could not be enabled in such way due to the consequences to ?non preview enabled code? but flexible constructor bodies, module import declarations, perhaps even scoped values and much more could be. Was this idea ever considered yet and if yes, what are the points against it? Best regards, Nick Hensel -------------- next part -------------- An HTML attachment was scrubbed... URL: From ethan at mccue.dev Wed Jul 16 15:26:29 2025 From: ethan at mccue.dev (Ethan McCue) Date: Wed, 16 Jul 2025 11:26:29 -0400 Subject: Behavior of Switch Statements without fallthrough Message-ID: I had a reader notice that the following code will not compile https://javabook.mccue.dev/switch/exhaustiveness enum Bird { TURKEY, EAGLE, WOODPECKER } boolean isScary(Bird bird) { switch (bird) { case TURKEY -> { return true; } case EAGLE -> { return true; } case WOODPECKER -> { return false; } } } void main() {} I can rationalize this by imagining that, in the case of a switch statement, there is no synthetic default inserted and thus it wouldn't be friendly to a new enum variant. That's not a spec-centered interpretation, but it would make sense to me. What doesn't make sense is that adding a case null allows it to compile enum Bird { TURKEY, EAGLE, WOODPECKER } boolean isScary(Bird bird) { switch (bird) { case TURKEY -> { return true; } case EAGLE -> { return true; } case WOODPECKER -> { return false; } case null -> { return true; } } } void main() {} This was pointed out as potentially being the relevant part of the spec https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 A set of case elements, P, covers a type T if one of the following cases applies: P covers a type U where T and U have the same erasure. P contains a pattern that is unconditional for T. T is a type variable with upper bound B and P covers B. T is an intersection type T1& ... &Tn and P covers Ti, for one of the types Ti (1? i ? n). The type T is an enum class type E and P contains all of the names of the enum constants of E. -------------- next part -------------- An HTML attachment was scrubbed... URL: From cushon at google.com Wed Jul 16 15:49:34 2025 From: cushon at google.com (Liam Miller-Cushon) Date: Wed, 16 Jul 2025 08:49:34 -0700 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: Message-ID: I think JLS 14.11.2 covers this: > An enhanced switch statement is one where ... there is a case ... null ... > For compatibility reasons, switch statements that are not enhanced switch statements are not required to be exhaustive. The first example without the 'case null' isn't an 'enhanced' switch, so it isn't required to be exhaustive, so it doesn't get the synthetic default that throws a MatchException. https://bugs.openjdk.org/browse/JDK-8345997 and https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html cover similar ground. On Wed, Jul 16, 2025 at 8:26?AM Ethan McCue wrote: > I had a reader notice that the following code will not compile > > https://javabook.mccue.dev/switch/exhaustiveness > > enum Bird { > TURKEY, > EAGLE, > WOODPECKER > } > > boolean isScary(Bird bird) { > switch (bird) { > case TURKEY -> { > return true; > } > case EAGLE -> { > return true; > } > case WOODPECKER -> { > return false; > } > } > } > > void main() {} > > I can rationalize this by imagining that, in the case of a switch > statement, there is no synthetic default inserted and thus it wouldn't be > friendly to a new enum variant. That's not a spec-centered interpretation, > but it would make sense to me. > > What doesn't make sense is that adding a case null allows it to compile > > enum Bird { > TURKEY, > EAGLE, > WOODPECKER > } > > boolean isScary(Bird bird) { > switch (bird) { > case TURKEY -> { > return true; > } > case EAGLE -> { > return true; > } > case WOODPECKER -> { > return false; > } > case null -> { > return true; > } > } > } > > void main() {} > > This was pointed out as potentially being the relevant part of the spec > > > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > > > A set of case elements, P, covers a type T if one of the following cases > applies: > P covers a type U where T and U have the same erasure. > P contains a pattern that is unconditional for T. > T is a type variable with upper bound B and P covers B. > T is an intersection type T1& ... &Tn and P covers Ti, for one of the > types Ti (1? i ? n). > The type T is an enum class type E and P contains all of the names of the > enum constants of E. > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay.horstmann at gmail.com Tue Jul 22 15:32:39 2025 From: cay.horstmann at gmail.com (Cay Horstmann) Date: Tue, 22 Jul 2025 17:32:39 +0200 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: Message-ID: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> There is more to this. Agreed that boolean isScary(Bird bird) { switch (bird) { case TURKEY -> { return true; } case EAGLE -> { return true; } case WOODPECKER -> { return false; } } } is not an enhanced switch. But neither is boolean isScary2(Bird bird) { return switch (bird) { case TURKEY -> true; case EAGLE -> true; case WOODPECKER -> false; }; } Yet the second method compiles. There is another rule, ?14.22 (https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22): ... a switch can complete normally if ... "The switch statement is not enhanced (?14.11.2) and its switch block does not contain a default label." This rule applies only to switch statements, not to switch expressions. IIRC, the thinking behind the treatment of switch statements in ?14.22 was that the enum might change in a separate compilation unit. Then the switch simply completes without matching any cases. In contrast, for switch expressions (and enhanced switch statements), a MatchException is thrown in that situation. In summary, here is what happens when no case applies to the selector: statement expression not enhanced completes throws ME enhanced throws ME throws ME As it says in JEP 361: The greater the divergence between switch expressions and switch statements, the more complex the language is to learn, and the more sharp edges there are for developers to cut themselves on. Cheers, Cay Il 16/07/2025 17:49, Liam Miller-Cushon ha scritto: > I think JLS 14.11.2 covers this: > > > An enhanced switch statement is one where ... there is a case ... null > ... > > For compatibility reasons, switch statements that are not enhanced switch statements are not required to be exhaustive. > > The first example without the 'case null' isn't an 'enhanced' switch, so it isn't required to be exhaustive, so it doesn't get the synthetic default that throws a MatchException. > > https://bugs.openjdk.org/browse/JDK-8345997 and https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html cover similar ground. > > On Wed, Jul 16, 2025 at 8:26?AM Ethan McCue > wrote: > > I had a reader notice that the following code will not compile > > https://javabook.mccue.dev/switch/exhaustiveness > > enum Bird { > ? ? TURKEY, > ? ? EAGLE, > ? ? WOODPECKER > } > > boolean isScary(Bird bird) { > ? ? switch (bird) { > ? ? ? ? case TURKEY -> { > ? ? ? ? ? ? return true; > ? ? ? ? } > ? ? ? ? case EAGLE -> { > ? ? ? ? ? ? return true; > ? ? ? ? } > ? ? ? ? case WOODPECKER -> { > ? ? ? ? ? ? return false; > ? ? ? ? } > ? ? } > } > > void main() {} > > I can rationalize this by imagining that, in the case of a switch statement, there is no synthetic default inserted and thus it wouldn't be friendly to a new enum variant. That's not a spec-centered interpretation, but it would make sense to me. > > What doesn't make sense is that adding a case null allows it to compile > > enum Bird { > ? ? TURKEY, > ? ? EAGLE, > ? ? WOODPECKER > } > > boolean isScary(Bird bird) { > ? ? switch (bird) { > ? ? ? ? case TURKEY -> { > ? ? ? ? ? ? return true; > ? ? ? ? } > ? ? ? ? case EAGLE -> { > ? ? ? ? ? ? return true; > ? ? ? ? } > ? ? ? ? case WOODPECKER -> { > ? ? ? ? ? ? return false; > ? ? ? ? } > ? ? ? ? case null -> { > ? ? ? ? ? ? return true; > ? ? ? ? } > ? ? } > } > > void main() {} > > This was pointed out as potentially being the relevant part of the spec > > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > > > A set of case elements, P, covers a type T if one of the following cases applies: > P covers a type U where T and U have the same erasure. > P contains a pattern that is unconditional for T. > T is a type variable with upper bound B and P covers B. > T is an intersection type T1& ... &Tn and P covers Ti, for one of the types Ti (1? i ? n). > The type T is an enum class type E and P contains all of the names of the enum constants of E. > > -- Cay S. Horstmann | https://horstmann.com From cushon at google.com Tue Jul 22 15:46:06 2025 From: cushon at google.com (Liam Miller-Cushon) Date: Tue, 22 Jul 2025 08:46:06 -0700 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: I think I'm mostly agreeing here, but note that the second example isn't an enhanced switch statement because it isn't a statement. 14.11.2 defines 'enhanced switch *statements*', the 'enhanced' concept doesn't apply to switch expressions. 15.28.1 defines additional rules for switch expressions and says they are required to be exhaustive and always get the MatchException. On Tue, Jul 22, 2025 at 8:32?AM Cay Horstmann wrote: > There is more to this. > > Agreed that > > boolean isScary(Bird bird) { > switch (bird) { > case TURKEY -> { > return true; > } > case EAGLE -> { > return true; > } > case WOODPECKER -> { > return false; > } > } > } > > is not an enhanced switch. But neither is > > boolean isScary2(Bird bird) { > return switch (bird) { > case TURKEY -> true; > case EAGLE -> true; > case WOODPECKER -> false; > }; > } > > Yet the second method compiles. > > There is another rule, ?14.22 ( > https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22): > ... a switch can complete normally if ... "The switch statement is not > enhanced (?14.11.2) and its switch block does not contain a default label." > > This rule applies only to switch statements, not to switch expressions. > > IIRC, the thinking behind the treatment of switch statements in ?14.22 was > that the enum might change in a separate compilation unit. Then the switch > simply completes without matching any cases. In contrast, for switch > expressions (and enhanced switch statements), a MatchException is thrown in > that situation. > > In summary, here is what happens when no case applies to the selector: > > statement expression > not enhanced completes throws ME > enhanced throws ME throws ME > > As it says in JEP 361: The greater the divergence between switch > expressions and switch statements, the more complex the language is to > learn, and the more sharp edges there are for developers to cut themselves > on. > > Cheers, > > Cay > > Il 16/07/2025 17:49, Liam Miller-Cushon ha scritto: > > I think JLS 14.11.2 covers this: > > > > > An enhanced switch statement is one where ... there is a case ... null > > ... > > > For compatibility reasons, switch statements that are not enhanced > switch statements are not required to be exhaustive. > > > > The first example without the 'case null' isn't an 'enhanced' switch, so > it isn't required to be exhaustive, so it doesn't get the synthetic default > that throws a MatchException. > > > > https://bugs.openjdk.org/browse/JDK-8345997 < > https://bugs.openjdk.org/browse/JDK-8345997> and > https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html < > https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html> > cover similar ground. > > > > On Wed, Jul 16, 2025 at 8:26?AM Ethan McCue ethan at mccue.dev>> wrote: > > > > I had a reader notice that the following code will not compile > > > > https://javabook.mccue.dev/switch/exhaustiveness < > https://javabook.mccue.dev/switch/exhaustiveness> > > > > enum Bird { > > TURKEY, > > EAGLE, > > WOODPECKER > > } > > > > boolean isScary(Bird bird) { > > switch (bird) { > > case TURKEY -> { > > return true; > > } > > case EAGLE -> { > > return true; > > } > > case WOODPECKER -> { > > return false; > > } > > } > > } > > > > void main() {} > > > > I can rationalize this by imagining that, in the case of a switch > statement, there is no synthetic default inserted and thus it wouldn't be > friendly to a new enum variant. That's not a spec-centered interpretation, > but it would make sense to me. > > > > What doesn't make sense is that adding a case null allows it to > compile > > > > enum Bird { > > TURKEY, > > EAGLE, > > WOODPECKER > > } > > > > boolean isScary(Bird bird) { > > switch (bird) { > > case TURKEY -> { > > return true; > > } > > case EAGLE -> { > > return true; > > } > > case WOODPECKER -> { > > return false; > > } > > case null -> { > > return true; > > } > > } > > } > > > > void main() {} > > > > This was pointed out as potentially being the relevant part of the > spec > > > > > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > < > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > > > > > > > > A set of case elements, P, covers a type T if one of the following > cases applies: > > P covers a type U where T and U have the same erasure. > > P contains a pattern that is unconditional for T. > > T is a type variable with upper bound B and P covers B. > > T is an intersection type T1& ... &Tn and P covers Ti, for one of > the types Ti (1? i ? n). > > The type T is an enum class type E and P contains all of the names > of the enum constants of E. > > > > > > -- > > Cay S. Horstmann | https://horstmann.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jul 22 16:06:12 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 22 Jul 2025 12:06:12 -0400 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: > As it says in JEP 361: The greater the divergence between switch > expressions and switch statements, the more complex the language is to > learn, and the more sharp edges there are for developers to cut > themselves on. We would love to give the same treatment to all switches; this is simpler and more uniform, which benefits almost everyone.? We can't get there immediately, but we can get there, but not without some small pain for someone. Right now, we have "all switches except legacy switches" (where legacy is the intersection of "doesn't use patterns, is a statement, doesn't use guards, etc") are exhaustive.? But it would surely be better to just get to "switches are exhaustive".? To do that, though, some existing code will stop compiling.? Fixing such code is "easy" (just add a do-nothing default), but it is a source-incompatible change.? The last time we did this was Java 9, where we reclaimed _ from the space of identifiers; we had to do go through a "deprecation" process which started with warnings, then suppressible errors, then errors.? And this consumes a finite tolerance that the ecosystem has for "forcing them to make changes".? So its possible, but to be approached carefully. From cay.horstmann at gmail.com Tue Jul 22 17:07:34 2025 From: cay.horstmann at gmail.com (Cay Horstmann) Date: Tue, 22 Jul 2025 19:07:34 +0200 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: Thank you, you are absolutely right. I re-read every mention of "enhanced" in the JLS, and have come to better appreciate the symmetry between "enhanced switch statements" and "switch expressions". What is the preferred name for a non-enhanced switch statement? Basic switch statement (to mirror the basic for statement in the JLS)? Legacy switch statement? Asking for a friend who has to update a book... Il 22/07/2025 17:46, Liam Miller-Cushon ha scritto: > I think I'm mostly agreeing here, but note that the second example isn't an enhanced switch?statement because it isn't a statement. 14.11.2 defines 'enhanced switch *statements*', the 'enhanced' concept doesn't apply to switch expressions. > > 15.28.1 defines additional rules for switch?expressions and says they are required to be exhaustive and always get the MatchException. > > > > On Tue, Jul 22, 2025 at 8:32?AM Cay Horstmann > wrote: > > There is more to this. > > Agreed that > > boolean isScary(Bird bird) { > ? ? ?switch (bird) { > ? ? ? ? ?case TURKEY -> { > ? ? ? ? ? ? ?return true; > ? ? ? ? ?} > ? ? ? ? ?case EAGLE -> { > ? ? ? ? ? ? ?return true; > ? ? ? ? } > ? ? ? ? case WOODPECKER -> { > ? ? ? ? ? ? return false; > ? ? ? ? } > ? ? ?} > } > > is not an enhanced switch. But neither is > > boolean isScary2(Bird bird) { > ? ? ?return switch (bird) { > ? ? ? ? ?case TURKEY -> true; > ? ? ? ? ?case EAGLE -> true; > ? ? ? ? ?case WOODPECKER -> false; > ? ? ?}; > } > > Yet the second method compiles. > > There is another rule, ?14.22 (https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22 ): ... a switch can complete normally if ... "The switch statement is not enhanced (?14.11.2) and its switch block does not contain a default label." > > This rule applies only to switch statements, not to switch expressions. > > IIRC, the thinking behind the treatment of switch statements in ?14.22 was that the enum might change in a separate compilation unit. Then the switch simply completes without matching any cases. In contrast, for switch expressions (and enhanced switch statements), a MatchException is thrown in that situation. > > In summary, here is what happens when no case applies to the selector: > > ? ? ? ? ? ? ? ?statement? ?expression > not enhanced? completes? ?throws ME > enhanced? ? ? throws ME? ?throws ME > > As it says in JEP 361: The greater the divergence between switch expressions and switch statements, the more complex the language is to learn, and the more sharp edges there are for developers to cut themselves on. > > Cheers, > > Cay > > Il 16/07/2025 17:49, Liam Miller-Cushon ha scritto: > > I think JLS 14.11.2 covers this: > > > >? > An enhanced switch statement is one where ... there is a case ... null > > ... > >? > For compatibility reasons, switch statements that are not enhanced switch statements are not required to be exhaustive. > > > > The first example without the 'case null' isn't an 'enhanced' switch, so it isn't required to be exhaustive, so it doesn't get the synthetic default that throws a MatchException. > > > > https://bugs.openjdk.org/browse/JDK-8345997 > and https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html > cover similar ground. > > > > On Wed, Jul 16, 2025 at 8:26?AM Ethan McCue >> wrote: > > > >? ? ?I had a reader notice that the following code will not compile > > > > https://javabook.mccue.dev/switch/exhaustiveness > > > > >? ? ?enum Bird { > >? ? ? ? ? TURKEY, > >? ? ? ? ? EAGLE, > >? ? ? ? ? WOODPECKER > >? ? ?} > > > >? ? ?boolean isScary(Bird bird) { > >? ? ? ? ? switch (bird) { > >? ? ? ? ? ? ? case TURKEY -> { > >? ? ? ? ? ? ? ? ? return true; > >? ? ? ? ? ? ? } > >? ? ? ? ? ? ? case EAGLE -> { > >? ? ? ? ? ? ? ? ? return true; > >? ? ? ? ? ? ? } > >? ? ? ? ? ? ? case WOODPECKER -> { > >? ? ? ? ? ? ? ? ? return false; > >? ? ? ? ? ? ? } > >? ? ? ? ? } > >? ? ?} > > > >? ? ?void main() {} > > > >? ? ?I can rationalize this by imagining that, in the case of a switch statement, there is no synthetic default inserted and thus it wouldn't be friendly to a new enum variant. That's not a spec-centered interpretation, but it would make sense to me. > > > >? ? ?What doesn't make sense is that adding a case null allows it to compile > > > >? ? ?enum Bird { > >? ? ? ? ? TURKEY, > >? ? ? ? ? EAGLE, > >? ? ? ? ? WOODPECKER > >? ? ?} > > > >? ? ?boolean isScary(Bird bird) { > >? ? ? ? ? switch (bird) { > >? ? ? ? ? ? ? case TURKEY -> { > >? ? ? ? ? ? ? ? ? return true; > >? ? ? ? ? ? ? } > >? ? ? ? ? ? ? case EAGLE -> { > >? ? ? ? ? ? ? ? ? return true; > >? ? ? ? ? ? ? } > >? ? ? ? ? ? ? case WOODPECKER -> { > >? ? ? ? ? ? ? ? ? return false; > >? ? ? ? ? ? ? } > >? ? ? ? ? ? ? case null -> { > >? ? ? ? ? ? ? ? ? return true; > >? ? ? ? ? ? ? } > >? ? ? ? ? } > >? ? ?} > > > >? ? ?void main() {} > > > >? ? ?This was pointed out as potentially being the relevant part of the spec > > > > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > > > > > > >? ? ?A set of case elements, P, covers a type T if one of the following cases applies: > >? ? ?P covers a type U where T and U have the same erasure. > >? ? ?P contains a pattern that is unconditional for T. > >? ? ?T is a type variable with upper bound B and P covers B. > >? ? ?T is an intersection type T1& ... &Tn and P covers Ti, for one of the types Ti (1? i ? n). > >? ? ?The type T is an enum class type E and P contains all of the names of the enum constants of E. > > > > > > -- > > Cay S. Horstmann | https://horstmann.com > -- Cay S. Horstmann | https://horstmann.com From kfogel at dawsoncollege.qc.ca Wed Jul 23 15:45:42 2025 From: kfogel at dawsoncollege.qc.ca (Kenneth Fogel) Date: Wed, 23 Jul 2025 15:45:42 +0000 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: To summarize, because there never was a switch expression it cannot be labelled as 'enhanced' while as there was the evil C-style switch we had to suffer with all these years, the new sensible switch is the enhanced switch. I do mean to be flippant. In the late 90s I worked with VB6. It had a Select Case that I felt made more sense that what C/C++ offered. I have been waiting since then for a switch at least as sensible as VB6. What we finally have is something superior to VB6, I think, its still early days. Now for an absurd statement. Can we deprecate the C-style switch? I understand why it cannot be done, no need to think of me as delusional, but can we at least send out an alert warning developers to avoid the old switch statement. If I was still in the classroom I'd teach the C-style switch like it was fire. Original fire can cook food but the enhanced fire we call a stove is much better. Despite my poor attempts at humour, I do enjoy these discussions. Ken PS: I also never liked break. Not going to miss it. PPS: Anyone who codes a return in a case block is a [insert insult here]. PPPS: Please get primitive pattern matching out of preview and into the fresh air -----Original Message----- From: amber-dev On Behalf Of Cay Horstmann Sent: July 22, 2025 1:08 PM To: Liam Miller-Cushon Cc: amber-dev at openjdk.org Subject: Re: Behavior of Switch Statements without fallthrough Thank you, you are absolutely right. I re-read every mention of "enhanced" in the JLS, and have come to better appreciate the symmetry between "enhanced switch statements" and "switch expressions". What is the preferred name for a non-enhanced switch statement? Basic switch statement (to mirror the basic for statement in the JLS)? Legacy switch statement? Asking for a friend who has to update a book... Il 22/07/2025 17:46, Liam Miller-Cushon ha scritto: > I think I'm mostly agreeing here, but note that the second example isn't an enhanced switch statement because it isn't a statement. 14.11.2 defines 'enhanced switch *statements*', the 'enhanced' concept doesn't apply to switch expressions. > > 15.28.1 defines additional rules for switch expressions and says they are required to be exhaustive and always get the MatchException. > > > > On Tue, Jul 22, 2025 at 8:32?AM Cay Horstmann > wrote: > > There is more to this. > > Agreed that > > boolean isScary(Bird bird) { > switch (bird) { > case TURKEY -> { > return true; > } > case EAGLE -> { > return true; > } > case WOODPECKER -> { > return false; > } > } > } > > is not an enhanced switch. But neither is > > boolean isScary2(Bird bird) { > return switch (bird) { > case TURKEY -> true; > case EAGLE -> true; > case WOODPECKER -> false; > }; > } > > Yet the second method compiles. > > There is another rule, ?14.22 (https://docs.oracle.com/javase/specs/jls/se21/html/jls-14.html#jls-14.22 ): ... a switch can complete normally if ... "The switch statement is not enhanced (?14.11.2) and its switch block does not contain a default label." > > This rule applies only to switch statements, not to switch expressions. > > IIRC, the thinking behind the treatment of switch statements in ?14.22 was that the enum might change in a separate compilation unit. Then the switch simply completes without matching any cases. In contrast, for switch expressions (and enhanced switch statements), a MatchException is thrown in that situation. > > In summary, here is what happens when no case applies to the selector: > > statement expression > not enhanced completes throws ME > enhanced throws ME throws ME > > As it says in JEP 361: The greater the divergence between switch expressions and switch statements, the more complex the language is to learn, and the more sharp edges there are for developers to cut themselves on. > > Cheers, > > Cay > > Il 16/07/2025 17:49, Liam Miller-Cushon ha scritto: > > I think JLS 14.11.2 covers this: > > > > > An enhanced switch statement is one where ... there is a case ... null > > ... > > > For compatibility reasons, switch statements that are not enhanced switch statements are not required to be exhaustive. > > > > The first example without the 'case null' isn't an 'enhanced' switch, so it isn't required to be exhaustive, so it doesn't get the synthetic default that throws a MatchException. > > > > https://bugs.openjdk.org/browse/JDK-8345997 > and https://mail.openjdk.org/pipermail/amber-dev/2024-December/009139.html > cover similar ground. > > > > On Wed, Jul 16, 2025 at 8:26?AM Ethan McCue >> wrote: > > > > I had a reader notice that the following code will not compile > > > > https://javabook.mccue.dev/switch/exhaustiveness > > > > > enum Bird { > > TURKEY, > > EAGLE, > > WOODPECKER > > } > > > > boolean isScary(Bird bird) { > > switch (bird) { > > case TURKEY -> { > > return true; > > } > > case EAGLE -> { > > return true; > > } > > case WOODPECKER -> { > > return false; > > } > > } > > } > > > > void main() {} > > > > I can rationalize this by imagining that, in the case of a switch statement, there is no synthetic default inserted and thus it wouldn't be friendly to a new enum variant. That's not a spec-centered interpretation, but it would make sense to me. > > > > What doesn't make sense is that adding a case null allows it to compile > > > > enum Bird { > > TURKEY, > > EAGLE, > > WOODPECKER > > } > > > > boolean isScary(Bird bird) { > > switch (bird) { > > case TURKEY -> { > > return true; > > } > > case EAGLE -> { > > return true; > > } > > case WOODPECKER -> { > > return false; > > } > > case null -> { > > return true; > > } > > } > > } > > > > void main() {} > > > > This was pointed out as potentially being the relevant part of the spec > > > > https://docs.oracle.com/javase/specs/jls/se24/html/jls-14.html#jls-14.11.1.1 > > > > > > > A set of case elements, P, covers a type T if one of the following cases applies: > > P covers a type U where T and U have the same erasure. > > P contains a pattern that is unconditional for T. > > T is a type variable with upper bound B and P covers B. > > T is an intersection type T1& ... &Tn and P covers Ti, for one of the types Ti (1? i ? n). > > The type T is an enum class type E and P contains all of the names of the enum constants of E. > > > > > > -- > > Cay S. Horstmann | https://horstmann.com/ > -- Cay S. Horstmann | https://horstmann.com/ From rob.ross at gmail.com Fri Jul 25 02:16:05 2025 From: rob.ross at gmail.com (Rob Ross) Date: Thu, 24 Jul 2025 19:16:05 -0700 Subject: String templates Message-ID: Hello list. First, I welcome suggestions and feedback on what kind of information is useful to contribute to the topic of string templates in Java. I have been developing in Python for about the last two years, but am now starting a new Java project for the first time in a while. And even though Python is full of cool features that would be nice to have in Java, I understand that just because a feature is cool in one language, "coolness" is not the only consideration in deciding whether or not to adopt it in another language. I just want to give my personal experience in string handling in Python, specifically "f-strings" or "formatted string literals". These are string literals but they can capture values of variables and methods defined in the current scope. You prefix the string literal with the letter 'f' (for format). E.g., num_hamburgers = 12 print( f"I have eaten {num_hamburgers} today at {time.now}.") As with printf() and similar string display methods, there are a plethora of ways to format each replacement field. This isn't a live template - the replacement fields capture the value at the point they are defined in the runtime and thereafter have the same string value. You can also store the template in a regular string and manually call a format method on it as your data changes as you can in Java. E.g., template: str = "Hello {name}, it's now {time} o'clock" name: str = "Rob" time: int = 12 print("template: " + template) print("formated: " + template.format(name=name, time=time)) print("f-string: " + f"Hello {name}, it's now {time} o'clock") # output: # template: Hello {name}, it's now {time} o'clock # formated: Hello Rob, it's now 12 o'clock # f-string: Hello Rob, it's now 12 o'clock Using format() behaves essentially identical to what Java has. But the simplicity of the f-string for capturing state really does increase my productivity in a meaningful way. In my last project I used f-strings for two primary use cases. 1. Debugging information during development 2. Formal representation of an object's state in a "toString()" context. I use the first case far more often. And yes I know how to use a debugger. :) I have just found that in many (most) cases, a few strategic println() or logger.info() statements are perfectly adequate for the task. These have a short lifecycle, sometimes existing only for the 5 minutes of debugging to identify a problem, or perhaps a little longer as scaffolding until my code solidifies and has the proper exceptions and logging handling in place. And for these cases, which occur every day in my life, the f-string format is much more helpful and less error prone than the current String format() method. The problem is that it is very easy to have a mismatch of arguments and format specifiers in Java, which results in me having to first debug my debugging! And reading such expressions also imposes a cognitive load that I do not feel with f-strings. A simple non-trivial example: ```Java String name = "Alice"; int age = 5; double score = 93.456; int rank = 2; String template = "Name: %1$-10s | Age: %2$02d | Score: %3$07.2f | Rank: #%4$03d"; String result = String.format(template, name, age, score, rank); System.out.println(result); ``` ```Python name = "Alice" age = 5 score = 93.456 rank = 2 result = f"Name: {name:<10} | Age: {age:02} | Score: {score:07.2f} | Rank: #{rank:03}" print(result) ``` I find it easier to scan the f-string than the equivalent Java formatted string. Now, here's a real-world example of code I am porting from Python to Java, as part of a JSON pretty-printer. In Python, in a particular context where I am displaying formatted keys (kf) and values (vf) of a Map member: indent_str is a string of blank spaces to align the key:value horizontally. Python: f"{indent_str}{OPEN_BRACE}{SPACE}{kf}{COLON}{SPACE}{vf}{SPACE}{CLOSE_BRACE}" the variables here are indent_str, kf, and vf, and the rest are constants. Using constants instead of literal characters has several benefits that most developers should understand. I also appreciate the larger signal-to-noise ratio that the constants display over inline characters. In Java, my first attempt to duplicate this was hilarious: "%s%s%s%s%s%s%s%s%s".formatted(indentString,OPEN_BRACE, SPACE, kf, COLON, SPACE, vf, SPACE, CLOSE_BRACE); Uhm, is that 8, or 9, or 10 %s ? hmm... So after some refactoring I ended up with this: "%s{ %s: %s }".formatted( indentString, kf, vf ) bye-bye constants, you're as useful to me as a 4-assed monkey. (South Park reference...) Is this "just as good?" Eh. Did I add an extra space somewhere? Did I forget a brace? Or did I add an extra one? And if I someday need to add a new argument, I need to add something in two places, and manually make sure to coordinate those.... sigh. So that's my contribution to the topic for the day. Am I just re-hashing obvious things that everyone knows about already? - Rob -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Fri Jul 25 19:53:02 2025 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Fri, 25 Jul 2025 14:53:02 -0500 Subject: String templates In-Reply-To: References: Message-ID: On Thu, Jul 24, 2025 at 9:16?PM Rob Ross wrote: > First, I welcome suggestions and feedback on what kind of information is > useful to contribute to the topic of string templates in Java. > There was some preliminary work on this but it got shelved for various reasons. I hope Brian will let me know if the following comments are out-of-scope... :) My own current thinking on this topic is that instead of trying to define the one true template syntax, Java should take a "pluggable syntax" approach to this problem. This would be roughly analogous to annotation processing: The compiler calls out to plug-ins (implementations of SyntaxProcessor say) to evaluate chunks of source code ("templates"). The plug-ins would in turn convert the templates into "recipes" for normal evaluation and pass them back to the compiler. Exactly what these "recipes" are is TBD. This would look similar to JEP 465 but would be fully agnostic about (a) the literals that define the templates and (b) how they are interpreted. Simple example equivalent to JEP 465 but with a different (better?) interpolation syntax: import com.example.syntax.SQL; public class MyClass { public PreparedStatement buildSQL(String name, int age) { return SQL."SELECT * FROM Person WHERE name = :name AND age = :age"; } } Key points... - The syntax for, and meaning of, "interpolation" in the template, if any, is determined entirely by the SyntaxProcessor. - The Java type of the evaluated template expression can be any Java type (ideally, determined *dynamically* by the SyntaxProcessor) - The *Literal* does not have to be a String, it could be any Java literal. Examples: Currency.'?', Year.2025, etc. - The SyntaxProcessor can "access" arbitrary Java expressions, i.e., it can pass them back to the compiler for (eventual) evaluation as part of the "recipe". This facilitates interpolation. Another simple example demonstrating a totally different "interpolation" that's more appropriate for an XSL transform: import com.example.xml.XSLT; import javax.xml.transform.*; public class MyClass { public void xmlSplitFullName(Source input, Result output, String fullNameTag) { XSLT.""" """.transform(input, output); } } -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.1993grajales at gmail.com Sat Jul 26 21:03:05 2025 From: david.1993grajales at gmail.com (david Grajales) Date: Sat, 26 Jul 2025 16:03:05 -0500 Subject: Thoughts on Array Initialization in JavaONE 2025 Message-ID: Dear Amber developers, I recently watched the JavaONE 2025 session titled *?A New Model for Java Object Initialization?* and was particularly intrigued by the proposed improvements to array initialization. https://www.youtube.com/watch?v=XtvR4kqK8lo I strongly agree that Java needs better mechanisms for initializing data structures in a concise, expressive, and stricter manner?similar in spirit to Python?s list comprehensions and aligned with Strict initialization, required for Valhalla. Such constructs can help avoid subtle bugs and the presence of unintended null values. However, I remain skeptical about the decision to focus this new model exclusively around arrays. As has been discussed over the past few months, arrays are not ideal as a default abstraction, especially for students or in enterprise applications. Arrays are a low-level construct with several limitations: - They do not integrate well with generics. - They are of fixed size. - They lack methods and flexibility. - They are syntactically and semantically inconsistent with the rest of the Java Collections Framework. In many ways, arrays are a legacy feature inherited from C/C++?much like the original switch statement?that carry forward certain limitations that Java has otherwise worked hard to overcome. Given these issues, Why not just create an small API that facilitates the creation of the most used data structures with strict initialization? For example: void main(){ // toArray var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + i); IO.println("Array: " + Arrays.toString(array)); // toList var list = StrictCollections.toList(5, i -> "List-" + i); IO.println("List: " + list); // toSet var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); IO.println("Set: " + set); var map = StrictCollections.toMap( 5, i -> "Key-" + i, i -> i * 100 ); IO.println("Map: " + map); } public static class StrictCollections { public static T[] toArray(Class clazz, int size, IntFunction function) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, size); // This could be a frozen array once these are ready for (int i = 0; i < size; i++) { array[i] = function.apply(i); } return array; } public static ArrayList toList(int size, IntFunction function) { var list = new ArrayList(size); for (int i = 0; i < size; i++) { list.add(function.apply(i)); } return list; } public static HashSet toSet(int size, IntFunction function) { List list = new ArrayList<>(size); for (int i = 0; i < size; i++) { list.add(function.apply(i)); } return new HashSet<>(list); } public static HashMap toMap(int size, IntFunction kFunction, IntFunction vFunction) { HashMap map = new HashMap<>(size); for (int i = 0; i < size; i++) { map.put(kFunction.apply(i), vFunction.apply(i)); } return map; } } While this is admittedly a rough sketch developed in just a few minutes, I believe a similar?much more thoroughly designed?approach could provide much greater flexibility with far less complexity than introducing a dedicated array-specific feature. It would also extend naturally to a broader range of use cases --Such as being able to be combined with the Stream API in a much more ergonomic way--. Furthermore, as value classes and parametric JVM start to make it into the language and the JVM, the advantages of arrays and primitive types will diminish further. In that context, arrays will become even less compelling in the future. If Java is to introduce a safe, expressive, and idiomatic strict initialization literal for data structures, I would argue it should primarily support List, Set, and Map?especially Map, which remains one of the least ergonomic structures to initialize in the language today, particularly when compared to alternatives in Dart, Python, or even JavaScript objects. Data structures that are much more used. Thank you so much for all your work and always yours -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sat Jul 26 21:48:49 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 26 Jul 2025 17:48:49 -0400 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: References: Message-ID: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> All of the points you raise that "arrays are not the abstraction you are looking for" are absolutely true -- and well understood. The goal of improving array creation is not to help arrays win market share away from collections. But there is a reason that the language has arrays, and that reason hasn't gone away.? Arrays are the bottom brick on which the tower of better data structures are built.? You can't have ArrayList or HashMap without arrays.? Arrays are part of the language for a reason.? As we improve the language, sometimes arrays have to improve with it.? (For example, if you have a non-implicitly-constructible value class NVA (one who has no valid default value), and someone wants to create an array of NVA![n], allowing the existing "zero the memory" array creation expression to create it would undermine the integrity of the runtime by exposing objects that are not in a valid state as determined by their constructor.? So we can't allow that, which means we have to provide something else.) If we hadn't found the need to improve other aspects of initialization, we probably wouldn't have bothered to improve array initialization.? But because we are improving initialization more broadly, we have to do the whole job.? Not being able to create interesting arrays linguistically would forever look like a weird omission. Your suggestion -- "why not just" not improve array creation linguistically, and shunt any sort of exotic array creation to a privileged API -- leaves the user with little explanation for why the tower stands up.? The bottom brick is not there, instead replaced by some sort of magic that seems to hold up the brick above it.? While we expect relatively few programmers to program with arrays (ideally, just the guy who maintains ArrayList and HashMap, and the like), we should provide linguistic mechanisms for properly using core linguistic building blocks. I can imagine three implicit lines of thought for why you think such a low-level mechanism should be performed by a privileged library rather than a language feature: ?- The easier we make it to use, the more people will use it, and you would like fewer people to use it (as would we.)? A scary-looking library will scare away more people than a pretty-looking language feature. ?- Language features are expensive, more expensive than libraries, so by shunting this to a library, we preserve resources to focus on more important things. ?- Array initialization appears to be competing for resources with features like collection literals, and you'd rather have the latter, so suggesting that we skip the former seems like it would bring the latter more quickly. These are appealing-sounding arguments, but they don't point to either usability wins or project-management wins.? Arrays are the right tool for some jobs.? Collections are the right tool for others (most others.)? But the way to encourage people to use the right tool is not to make the other tools harder to use.? (We too would like to have linguistic support for creating sets, lists, maps, etc, but that feature is not competing with arrays, its waiting for something else.)? Nor is the cost of a privileged array-construction API significantly cheaper than a language feature. Cheers, -Brian On 7/26/2025 5:03 PM, david Grajales wrote: > > Dear Amber developers, > > I recently watched the JavaONE 2025 session titled /?A New Model for > Java Object Initialization?/?and was particularly intrigued by the > proposed improvements to array initialization. > > https://www.youtube.com/watch?v=XtvR4kqK8lo > > > I strongly agree that Java needs better mechanisms for initializing > data structures in a concise, expressive, and stricter manner?similar > in spirit to Python?s list comprehensions and aligned with Strict > initialization, required for Valhalla. Such constructs can help avoid > subtle bugs and the presence of unintended |null|?values. However, I > remain skeptical about the decision to focus this new model > exclusively around arrays. > > As has been discussed over the past few months, arrays are not ideal > as a default abstraction, especially for students or in enterprise > applications. Arrays are a low-level construct with several limitations: > > * > > They do not integrate well with generics. > > * > > They are of fixed size. > > * > > They lack methods and flexibility. > > * > > They are syntactically and semantically inconsistent with the rest > of the Java Collections Framework. > > In many ways, arrays are a legacy feature inherited from C/C++?much > like the original |switch|?statement?that carry forward certain > limitations that Java has otherwise worked hard to overcome. > > Given these issues, Why not just create an small API that facilitates > the creation of the most used data structures with strict initialization? > > For example: > > > void main(){ > > > ? ? // toArray > > ? ? var array = StrictCollections.toArray(String.class, 5, i -> > "Item-" + i); > > ? ? IO.println("Array: " + Arrays.toString(array)); > > > ? ? // toList > > ? ? var list = StrictCollections.toList(5, i -> "List-" + i); > > ? ? IO.println("List: " + list); > > > ? ? // toSet > > ? ? var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); > > ? ? IO.println("Set: " + set); > > > > ? ? var map = StrictCollections.toMap( > > ? ? ? ? 5, > > ? ? ? ? i -> "Key-" + i, > > ? ? ? ? i -> i * 100 > > ? ? ); > > ? ? IO.println("Map: " + map); > > > } > > > > public static class StrictCollections { > > > ? ? public static T[] toArray(Class clazz, int size, > IntFunction function) { > > ? ? ? ? @SuppressWarnings("unchecked") > > ? ? ? ? T[] array = (T[]) Array.newInstance(clazz, size); // This > could be a frozen array once these are ready > > ? ? ? ? for (int i = 0; i < size; i++) { > > ? ? ? ? ? ? array[i] = function.apply(i); > > ? ? ? ? } > > ? ? ? ? return array; > > ? ? } > > > ? ? public static ArrayList toList(int size, IntFunction > function) { > > ? ? ? ? var list = new ArrayList(size); > > ? ? ? ? for (int i = 0; i < size; i++) { > > ? ? ? ? ? ? list.add(function.apply(i)); > > ? ? ? ? } > > ? ? ? ? return list; > > ? ? } > > > ? ? public static HashSet toSet(int size, IntFunction > function) { > > ? ? ? ? List list = new ArrayList<>(size); > > ? ? ? ? for (int i = 0; i < size; i++) { > > ? ? ? ? ? ? list.add(function.apply(i)); > > ? ? ? ? } > > ? ? ? ? return new HashSet<>(list); > > ? ? } > > > ? ? public static HashMap toMap(int size, IntFunction > kFunction, IntFunction vFunction) { > > ? ? ? ? HashMap map = new HashMap<>(size); > > ? ? ? ? for (int i = 0; i < size; i++) { > > ? ? ? ? ? ? map.put(kFunction.apply(i), vFunction.apply(i)); > > ? ? ? ? } > > ? ? ? ? return map; > > ? ? } > > } > > While this is admittedly a rough sketch developed in just a few > minutes, I believe a similar?much more thoroughly designed?approach > could provide much greater flexibility with far less complexity than > introducing a dedicated array-specific feature. It would also extend > naturally to a broader range of use cases --Such as being able to be > combined with the Stream API in a much more ergonomic way--. > Furthermore, as value classes and parametric JVM start to make it into > the language and the JVM, the advantages of arrays and primitive types > will diminish further. In that context, arrays will become even less > compelling in the future. > > If Java is to introduce a safe, expressive, and idiomatic strict > initialization literal for data structures, I would argue it should > primarily support |List|, |Set|, and |Map|?especially |Map|, which > remains one of the least ergonomic structures to initialize in the > language today, particularly when compared to alternatives in Dart, > Python, or even JavaScript objects. Data structures that are much more > used. > > > Thank you so much for all your work and always yours > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.1993grajales at gmail.com Sun Jul 27 01:30:03 2025 From: david.1993grajales at gmail.com (david Grajales) Date: Sat, 26 Jul 2025 20:30:03 -0500 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> Message-ID: Hi Brian, Thank you for your thoughtful and detailed response?I really appreciate the clarity. I just wanted to note that this feature closely resembles trailing lambdas or Clojure-style expressions. While I?m not opposed to it (quite the opposite), I do wonder if limiting it to arrays might introduce some inconsistency in the language. For what you say I will take that arrays are important enough at low level to stand another oddity, but this may raise expectations for a more general form in the future (Not just for collections but general). Thanks again and best wishes for you and all the team. Always yours. - David El s?b, 26 jul 2025 a la(s) 4:48?p.m., Brian Goetz (brian.goetz at oracle.com) escribi?: > All of the points you raise that "arrays are not the abstraction you are > looking for" are absolutely true -- and well understood. The goal of > improving array creation is not to help arrays win market share away from > collections. > > But there is a reason that the language has arrays, and that reason hasn't > gone away. Arrays are the bottom brick on which the tower of better data > structures are built. You can't have ArrayList or HashMap without arrays. > Arrays are part of the language for a reason. As we improve the language, > sometimes arrays have to improve with it. (For example, if you have a > non-implicitly-constructible value class NVA (one who has no valid default > value), and someone wants to create an array of NVA![n], allowing the > existing "zero the memory" array creation expression to create it would > undermine the integrity of the runtime by exposing objects that are not in > a valid state as determined by their constructor. So we can't allow that, > which means we have to provide something else.) > > If we hadn't found the need to improve other aspects of initialization, we > probably wouldn't have bothered to improve array initialization. But > because we are improving initialization more broadly, we have to do the > whole job. Not being able to create interesting arrays linguistically > would forever look like a weird omission. > > Your suggestion -- "why not just" not improve array creation > linguistically, and shunt any sort of exotic array creation to a privileged > API -- leaves the user with little explanation for why the tower stands > up. The bottom brick is not there, instead replaced by some sort of magic > that seems to hold up the brick above it. While we expect relatively few > programmers to program with arrays (ideally, just the guy who maintains > ArrayList and HashMap, and the like), we should provide linguistic > mechanisms for properly using core linguistic building blocks. > > I can imagine three implicit lines of thought for why you think such a > low-level mechanism should be performed by a privileged library rather than > a language feature: > > - The easier we make it to use, the more people will use it, and you > would like fewer people to use it (as would we.) A scary-looking library > will scare away more people than a pretty-looking language feature. > - Language features are expensive, more expensive than libraries, so by > shunting this to a library, we preserve resources to focus on more > important things. > - Array initialization appears to be competing for resources with > features like collection literals, and you'd rather have the latter, so > suggesting that we skip the former seems like it would bring the latter > more quickly. > > These are appealing-sounding arguments, but they don't point to either > usability wins or project-management wins. Arrays are the right tool for > some jobs. Collections are the right tool for others (most others.) But > the way to encourage people to use the right tool is not to make the other > tools harder to use. (We too would like to have linguistic support for > creating sets, lists, maps, etc, but that feature is not competing with > arrays, its waiting for something else.) Nor is the cost of a privileged > array-construction API significantly cheaper than a language feature. > > Cheers, > -Brian > > > > > > > > > > On 7/26/2025 5:03 PM, david Grajales wrote: > > Dear Amber developers, > > I recently watched the JavaONE 2025 session titled *?A New Model for Java > Object Initialization?* and was particularly intrigued by the proposed > improvements to array initialization. > > https://www.youtube.com/watch?v=XtvR4kqK8lo > > > I strongly agree that Java needs better mechanisms for initializing data > structures in a concise, expressive, and stricter manner?similar in spirit > to Python?s list comprehensions and aligned with Strict initialization, > required for Valhalla. Such constructs can help avoid subtle bugs and the > presence of unintended null values. However, I remain skeptical about the > decision to focus this new model exclusively around arrays. > > As has been discussed over the past few months, arrays are not ideal as a > default abstraction, especially for students or in enterprise applications. > Arrays are a low-level construct with several limitations: > > - > > They do not integrate well with generics. > - > > They are of fixed size. > - > > They lack methods and flexibility. > - > > They are syntactically and semantically inconsistent with the rest of > the Java Collections Framework. > > In many ways, arrays are a legacy feature inherited from C/C++?much like > the original switch statement?that carry forward certain limitations that > Java has otherwise worked hard to overcome. > > Given these issues, Why not just create an small API that facilitates the > creation of the most used data structures with strict initialization? > > For example: > > > void main(){ > > > // toArray > > var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + > i); > > IO.println("Array: " + Arrays.toString(array)); > > > // toList > > var list = StrictCollections.toList(5, i -> "List-" + i); > > IO.println("List: " + list); > > > // toSet > > var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); > > IO.println("Set: " + set); > > > > var map = StrictCollections.toMap( > > 5, > > i -> "Key-" + i, > > i -> i * 100 > > ); > > IO.println("Map: " + map); > > > > > } > > > > public static class StrictCollections { > > > public static T[] toArray(Class clazz, int size, IntFunction > function) { > > @SuppressWarnings("unchecked") > > T[] array = (T[]) Array.newInstance(clazz, size); // This could be > a frozen array once these are ready > > for (int i = 0; i < size; i++) { > > array[i] = function.apply(i); > > } > > return array; > > } > > > public static ArrayList toList(int size, IntFunction > function) { > > var list = new ArrayList(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return list; > > } > > > public static HashSet toSet(int size, IntFunction function) { > > List list = new ArrayList<>(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return new HashSet<>(list); > > } > > > public static HashMap toMap(int size, IntFunction > kFunction, IntFunction vFunction) { > > HashMap map = new HashMap<>(size); > > for (int i = 0; i < size; i++) { > > map.put(kFunction.apply(i), vFunction.apply(i)); > > } > > return map; > > } > > } > > While this is admittedly a rough sketch developed in just a few minutes, I > believe a similar?much more thoroughly designed?approach could provide much > greater flexibility with far less complexity than introducing a dedicated > array-specific feature. It would also extend naturally to a broader range > of use cases --Such as being able to be combined with the Stream API in a > much more ergonomic way--. Furthermore, as value classes and parametric JVM > start to make it into the language and the JVM, the advantages of arrays > and primitive types will diminish further. In that context, arrays will > become even less compelling in the future. > > If Java is to introduce a safe, expressive, and idiomatic strict > initialization literal for data structures, I would argue it should > primarily support List, Set, and Map?especially Map, which remains one of > the least ergonomic structures to initialize in the language today, > particularly when compared to alternatives in Dart, Python, or even > JavaScript objects. Data structures that are much more used. > > > Thank you so much for all your work and always yours > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From atonita at proton.me Sun Jul 27 09:09:14 2025 From: atonita at proton.me (Aaryn Tonita) Date: Sun, 27 Jul 2025 09:09:14 +0000 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: Since we are talking about deprecation, > But it would surely be better to just get to "switches are exhaustive". To do that, though, some existing code will stop compiling. > Now for an absurd statement. Can we deprecate the C-style switch? I understand why it cannot be done, no need to think of me as delusional, but can we at least send out an alert warning developers to avoid the old switch statement. Doesn't Java benefit more than other languages here? Rust recently moved forward with the idea of editions where legacy code would continue to compile with an older edition of the language. The compiler would still get better in time, (they wouldn't be stuck on an older compiler) and the code would be importable from newer editions. Why can't Java have something similar? The benefit Java has is that it targets the JVM (ok, rust targets LLVM IR) and an older edition can compile to the latest version of the bytecode if the compiler supported it. The language breaking features aren't necessarily JVM breakage. Old code could compile, developers could bugfix and update to latest compiler versions without breaking their existing code, but if they want to modernize their Java, then the code breaks but they have decided to put in the effort. I would love to have such a breaking change where implicit null is gone, where arrays require initialization, where switches have no breaks and fall throughs. Where my old code continues to compile on the latest compiler but on an older edition of the language. Is the effort on the compiler team too great? From forax at univ-mlv.fr Sun Jul 27 13:23:53 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 27 Jul 2025 15:23:53 +0200 (CEST) Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: <927258414.4991279.1753622633602.JavaMail.zimbra@univ-eiffel.fr> ----- Original Message ----- > From: "Aaryn Tonita" > To: "amber-dev" > Sent: Sunday, July 27, 2025 11:09:14 AM > Subject: RE: Behavior of Switch Statements without fallthrough > Since we are talking about deprecation, > >> But it would surely be better to just get to "switches are exhaustive". To do >> that, though, some existing code will stop compiling. > >> Now for an absurd statement. Can we deprecate the C-style switch? I understand >> why it cannot be done, no need to think of me as delusional, but can we at >> least send out an alert warning developers to avoid the old switch statement. > > Doesn't Java benefit more than other languages here? Rust recently moved forward > with the idea of editions where legacy code would continue to compile with an > older edition of the language. The compiler would still get better in time, > (they wouldn't be stuck on an older compiler) and the code would be importable > from newer editions. > > Why can't Java have something similar? The benefit Java has is that it targets > the JVM (ok, rust targets LLVM IR) and an older edition can compile to the > latest version of the bytecode if the compiler supported it. The language > breaking features aren't necessarily JVM breakage. > > Old code could compile, developers could bugfix and update to latest compiler > versions without breaking their existing code, but if they want to modernize > their Java, then the code breaks but they have decided to put in the effort. > > I would love to have such a breaking change where implicit null is gone, where > arrays require initialization, where switches have no breaks and fall throughs. > Where my old code continues to compile on the latest compiler but on an older > edition of the language. > > Is the effort on the compiler team too great? Editions in Rust are equivalent to Java versions. A Java version can break old codes, by example, Java 10 introduces the keyword 'var', so an old code that uses 'var' as a type now behave differently, but we know that there are very few codes (if any) that will use 'var' as a type. The main reason to not introduce a "real" breaking change* (in Java or in Rust) is to not fracture the ecosystem of libraries, with some libraries only supporting the old version, others only supporting the new version and libraries trying to support both at the same time (relying on black magic). Python 2/Python 3 is a good example of what happen if you introduce a breaking change, despite the breaking change occurring more than 17 years ago, my lab is still using apps in Python 2 (because those apps have dependencies that will never be updated to support Python 3). Java is fundamentally about composition of libraries for free, you can not compose libraries in a fractured ecosystem. regards, R?mi From ethan at mccue.dev Sun Jul 27 13:48:22 2025 From: ethan at mccue.dev (Ethan McCue) Date: Sun, 27 Jul 2025 09:48:22 -0400 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: > Rust recently moved forward with the idea of editions Rust added editions a decade ago. Not important, but stuff like that always scores a critical hit on my psyche. > Why can't Java have something similar? > I would love to have such a breaking change where implicit null is gone, where arrays require initialization, where switches have no breaks and fall throughs. Where my old code continues to compile on the latest compiler but on an older edition of the language. The problem isn't that doing this is mechanically impossible. There is already a mechanism for compiling for older releases (--release). This is comparable to editions. The problem is that - while each successive release of the Java language is technically a new and different language - up til now the changes have been largely accretive. Java 25 is not a strict superset of Java 1.1 (Java 1.1 can have assert as an identifier and more), but it almost is. This is what preserves the ship of theseus illusion. If you break this illusion significantly you make a Java2. Is that worthwhile? Well, there are discussions around null restriction and a "flippening" there, classes being open for extension by default is unideal, and hey while we're at it... There are many things that you might want to change. Some of these are maybe worthwhile, some maybe not. All changes that make existing code no longer compile need a really good justification. > switches have no breaks and fall throughs This one in particular can be achieved via addition, not subtraction. If you don't want to use the switch with fallthrough, do not. > Is the effort on the compiler team too great? My outside read of the situation is that this is rarely the case. The implied effort on the part of the wider ecosystem is the greater factor. On Sun, Jul 27, 2025 at 6:59?AM Aaryn Tonita wrote: > Since we are talking about deprecation, > > > But it would surely be better to just get to "switches are exhaustive". > To do that, though, some existing code will stop compiling. > > > Now for an absurd statement. Can we deprecate the C-style switch? I > understand why it cannot be done, no need to think of me as delusional, but > can we at least send out an alert warning developers to avoid the old > switch statement. > > Doesn't Java benefit more than other languages here? Rust recently moved > forward with the idea of editions where legacy code would continue to > compile with an older edition of the language. The compiler would still get > better in time, (they wouldn't be stuck on an older compiler) and the code > would be importable from newer editions. > > Why can't Java have something similar? The benefit Java has is that it > targets the JVM (ok, rust targets LLVM IR) and an older edition can compile > to the latest version of the bytecode if the compiler supported it. The > language breaking features aren't necessarily JVM breakage. > > Old code could compile, developers could bugfix and update to latest > compiler versions without breaking their existing code, but if they want to > modernize their Java, then the code breaks but they have decided to put in > the effort. > > I would love to have such a breaking change where implicit null is gone, > where arrays require initialization, where switches have no breaks and fall > throughs. Where my old code continues to compile on the latest compiler but > on an older edition of the language. > > Is the effort on the compiler team too great? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sun Jul 27 14:58:50 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 27 Jul 2025 10:58:50 -0400 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> Message-ID: <2bff20ad-d905-4513-a647-b9a21d59f3bd@oracle.com> Ethan has this right.? What Aaryn is asking for here is really another version of the old "why don't we get rid of all the 'mistakes' and make a Java 2" canard.? (Which is surely fun to think about -- though harder than you probably think to build consensus on.) On 7/27/2025 9:48 AM, Ethan McCue wrote: > > Rust recently moved forward with the idea of editions > > Rust added editions a decade ago. Not important, but stuff like that > always scores a critical hit on my psyche. > > > Why can't Java have something similar? > > I would love to have such a breaking change where implicit null is > gone, where arrays require initialization, where switches have no > breaks and fall throughs. Where my old code continues to compile on > the latest compiler but on an older edition of the language. > > The problem isn't that doing this is mechanically impossible. There is > already a mechanism for compiling for older releases (--release). This > is comparable to editions. > > The problem is that - while each successive release of the Java > language is technically a new and different language - up til now the > changes have been largely accretive. Java 25 is not a strict superset > of Java 1.1 (Java 1.1 can have assert?as an identifier and more), but > it almost is. This is what preserves the ship of theseus illusion. If > you break this illusion significantly you make a Java2. > > Is that worthwhile? Well, there are discussions around null > restriction and a "flippening" there, classes being open for extension > by default is unideal, and hey while we're at it... > > There are many things that you might want to change. Some of these are > maybe worthwhile, some maybe not. All changes that make existing code > no longer compile need a really good justification. > > > switches have no breaks and fall throughs > > This one in particular can be achieved via addition, not subtraction. > If you don't want to use the switch with fallthrough, do not. > > > Is the effort on the compiler team too great? > > My outside read?of?the?situation is that this is rarely the case. The > implied effort on the part of the wider ecosystem is the greater factor. > > > > On Sun, Jul 27, 2025 at 6:59?AM Aaryn Tonita wrote: > > Since we are talking about deprecation, > > > But it would surely be better to just get to "switches are > exhaustive".? To do that, though, some existing code will stop > compiling. > > > Now for an absurd statement. Can we deprecate the C-style > switch? I understand why it cannot be done, no need to think of me > as delusional, but can we at least send out an alert warning > developers to avoid the old switch statement. > > Doesn't Java benefit more than other languages here? Rust recently > moved forward with the idea of editions where legacy code would > continue to compile with an older edition of the language. The > compiler would still get better in time, (they wouldn't be stuck > on an older compiler) and the code would be importable from newer > editions. > > Why can't Java have something similar? The benefit Java has is > that it targets the JVM (ok, rust targets LLVM IR) and an older > edition can compile to the latest version of the bytecode if the > compiler supported it. The language breaking features aren't > necessarily JVM breakage. > > Old code could compile, developers could bugfix and update to > latest compiler versions without breaking their existing code, but > if they want to modernize their Java, then the code breaks but > they have decided to put in the effort. > > I would love to have such a breaking change where implicit null is > gone, where arrays require initialization, where switches have no > breaks and fall throughs. Where my old code continues to compile > on the latest compiler but on an older edition of the language. > > Is the effort on the compiler team too great? > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Sun Jul 27 16:08:04 2025 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 27 Jul 2025 18:08:04 +0200 (CEST) Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> Message-ID: <28312021.5047976.1753632484479.JavaMail.zimbra@univ-eiffel.fr> > From: "Brian Goetz" > To: "david Grajales" , "amber-dev" > > Sent: Saturday, July 26, 2025 11:48:49 PM > Subject: Re: Thoughts on Array Initialization in JavaONE 2025 > All of the points you raise that "arrays are not the abstraction you are looking > for" are absolutely true -- and well understood. The goal of improving array > creation is not to help arrays win market share away from collections. > But there is a reason that the language has arrays, and that reason hasn't gone > away. Arrays are the bottom brick on which the tower of better data structures > are built. You can't have ArrayList or HashMap without arrays. Arrays are part > of the language for a reason. As we improve the language, sometimes arrays have > to improve with it. (For example, if you have a non-implicitly-constructible > value class NVA (one who has no valid default value), and someone wants to > create an array of NVA![n], allowing the existing "zero the memory" array > creation expression to create it would undermine the integrity of the runtime > by exposing objects that are not in a valid state as determined by their > constructor. So we can't allow that, which means we have to provide something > else.) > If we hadn't found the need to improve other aspects of initialization, we > probably wouldn't have bothered to improve array initialization. But because we > are improving initialization more broadly, we have to do the whole job. Not > being able to create interesting arrays linguistically would forever look like > a weird omission. > Your suggestion -- "why not just" not improve array creation linguistically, and > shunt any sort of exotic array creation to a privileged API -- leaves the user > with little explanation for why the tower stands up. The bottom brick is not > there, instead replaced by some sort of magic that seems to hold up the brick > above it. While we expect relatively few programmers to program with arrays > (ideally, just the guy who maintains ArrayList and HashMap, and the like), we > should provide linguistic mechanisms for properly using core linguistic > building blocks. > I can imagine three implicit lines of thought for why you think such a low-level > mechanism should be performed by a privileged library rather than a language > feature: > - The easier we make it to use, the more people will use it, and you would like > fewer people to use it (as would we.) A scary-looking library will scare away > more people than a pretty-looking language feature. > - Language features are expensive, more expensive than libraries, so by shunting > this to a library, we preserve resources to focus on more important things. > - Array initialization appears to be competing for resources with features like > collection literals, and you'd rather have the latter, so suggesting that we > skip the former seems like it would bring the latter more quickly. > These are appealing-sounding arguments, but they don't point to either usability > wins or project-management wins. Arrays are the right tool for some jobs. > Collections are the right tool for others (most others.) But the way to > encourage people to use the right tool is not to make the other tools harder to > use. (We too would like to have linguistic support for creating sets, lists, > maps, etc, but that feature is not competing with arrays, its waiting for > something else.) Nor is the cost of a privileged array-construction API > significantly cheaper than a language feature. I always flip-flop between thinking that arrays are redeemable and losing all hope about them :) I think that the solution to our problem is to use value classes, after all, a value class allows abstraction without the runtime cost, right, so why not eating our own dog food ? Why not using array wrapped into a value class that implements the List interface ? By example, here is a List that allows only to access to an element of the List only if it has been initialized first (using a watermark), value class WatermarkedList implements List { E[] array; int watermark; // private constructor + static method WatermarkedList append(E element) { array[watermark] = element; return new WatermarkedList<>(array, watermark + 1); } E get(int index) { Objects.checkIndex(index, watermark); return array[index]; } int size() { return watermark; } WatermarkedList copyOf(int newCapacity) { ... } ... } Here the array can be initialized with zeroes (using a "JDK restricted" method) and a WatermarkedList is still safe to be used with element that are NVA. I think the JDK can define few of those lightweight Lists that can be used as primitive by anyone wanting to implement more complex data structures (ArrayList, HashMap, etc). > Cheers, > -Brian regards, R?mi > On 7/26/2025 5:03 PM, david Grajales wrote: >> Dear Amber developers, >> I recently watched the JavaONE 2025 session titled ?A New Model for Java Object >> Initialization? and was particularly intrigued by the proposed improvements to >> array initialization. >> [ https://www.youtube.com/watch?v=XtvR4kqK8lo | >> https://www.youtube.com/watch?v=XtvR4kqK8lo ] >> I strongly agree that Java needs better mechanisms for initializing data >> structures in a concise, expressive, and stricter manner?similar in spirit to >> Python?s list comprehensions and aligned with Strict initialization, required >> for Valhalla. Such constructs can help avoid subtle bugs and the presence of >> unintended null values. However, I remain skeptical about the decision to focus >> this new model exclusively around arrays. >> As has been discussed over the past few months, arrays are not ideal as a >> default abstraction, especially for students or in enterprise applications. >> Arrays are a low-level construct with several limitations: >> * >> They do not integrate well with generics. >> * >> They are of fixed size. >> * >> They lack methods and flexibility. >> * >> They are syntactically and semantically inconsistent with the rest of the Java >> Collections Framework. >> In many ways, arrays are a legacy feature inherited from C/C++?much like the >> original switch statement?that carry forward certain limitations that Java has >> otherwise worked hard to overcome. >> Given these issues, Why not just create an small API that facilitates the >> creation of the most used data structures with strict initialization? >> For example: >> void main(){ >> // toArray >> var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + i); >> IO.println("Array: " + Arrays.toString(array)); >> // toList >> var list = StrictCollections.toList(5, i -> "List-" + i); >> IO.println("List: " + list); >> // toSet >> var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); >> IO.println("Set: " + set); >> var map = StrictCollections.toMap( >> 5, >> i -> "Key-" + i, >> i -> i * 100 >> ); >> IO.println("Map: " + map); >> } >> public static class StrictCollections { >> public static T[] toArray(Class clazz, int size, IntFunction function) >> { >> @SuppressWarnings("unchecked") >> T[] array = (T[]) Array.newInstance(clazz, size); // This could be a frozen >> array once these are ready >> for (int i = 0; i < size; i++) { >> array[i] = function.apply(i); >> } >> return array; >> } >> public static ArrayList toList(int size, IntFunction function) { >> var list = new ArrayList(size); >> for (int i = 0; i < size; i++) { >> list.add(function.apply(i)); >> } >> return list; >> } >> public static HashSet toSet(int size, IntFunction function) { >> List list = new ArrayList<>(size); >> for (int i = 0; i < size; i++) { >> list.add(function.apply(i)); >> } >> return new HashSet<>(list); >> } >> public static HashMap toMap(int size, IntFunction kFunction, >> IntFunction vFunction) { >> HashMap map = new HashMap<>(size); >> for (int i = 0; i < size; i++) { >> map.put(kFunction.apply(i), vFunction.apply(i)); >> } >> return map; >> } >> } >> While this is admittedly a rough sketch developed in just a few minutes, I >> believe a similar?much more thoroughly designed?approach could provide much >> greater flexibility with far less complexity than introducing a dedicated >> array-specific feature. It would also extend naturally to a broader range of >> use cases --Such as being able to be combined with the Stream API in a much >> more ergonomic way--. Furthermore, as value classes and parametric JVM start to >> make it into the language and the JVM, the advantages of arrays and primitive >> types will diminish further. In that context, arrays will become even less >> compelling in the future. >> If Java is to introduce a safe, expressive, and idiomatic strict initialization >> literal for data structures, I would argue it should primarily support List , >> Set , and Map ?especially Map , which remains one of the least ergonomic >> structures to initialize in the language today, particularly when compared to >> alternatives in Dart, Python, or even JavaScript objects. Data structures that >> are much more used. >> Thank you so much for all your work and always yours -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Sun Jul 27 22:56:41 2025 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Sun, 27 Jul 2025 17:56:41 -0500 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: <2bff20ad-d905-4513-a647-b9a21d59f3bd@oracle.com> References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> <2bff20ad-d905-4513-a647-b9a21d59f3bd@oracle.com> Message-ID: I'm not convinced that a "Java2" hard break is a good idea. But for the sake of argument suppose it was... Then instead of just declaring a "Java2", a smaller baby step in that direction would be to define a set of the "best practices" that would likely constitute such a thing, give it a catchy name like "The Modern Java Standard", and add a new lint warning flag -Xlint:modern-java that would warn about any non-compliant usage. The key point is that this could be done without anyone (JDK or developer) having to actually commit to anything. It would just be saying "It's *possible* in the future that Java might have a hard break from the past and if you would like to be conformant with that as-yet-not-fully-decided-and-purely-theoretical-at-this-point possibility then turn on this flag". Later in the distant future the feasibility of a real "Java2" could then be informed by the community's reaction, for example, by surveying how many projects are being built with -Werror and that lint flag enabled, etc. -Archie On Sun, Jul 27, 2025 at 9:59?AM Brian Goetz wrote: > Ethan has this right. What Aaryn is asking for here is really another > version of the old "why don't we get rid of all the 'mistakes' and make a > Java 2" canard. (Which is surely fun to think about -- though harder than > you probably think to build consensus on.) > > > > > > > On 7/27/2025 9:48 AM, Ethan McCue wrote: > > > Rust recently moved forward with the idea of editions > > Rust added editions a decade ago. Not important, but stuff like that > always scores a critical hit on my psyche. > > > Why can't Java have something similar? > > I would love to have such a breaking change where implicit null is gone, > where arrays require initialization, where switches have no breaks and fall > throughs. Where my old code continues to compile on the latest compiler but > on an older edition of the language. > > The problem isn't that doing this is mechanically impossible. There is > already a mechanism for compiling for older releases (--release). This is > comparable to editions. > > The problem is that - while each successive release of the Java language > is technically a new and different language - up til now the changes have > been largely accretive. Java 25 is not a strict superset of Java 1.1 (Java > 1.1 can have assert as an identifier and more), but it almost is. This is > what preserves the ship of theseus illusion. If you break this illusion > significantly you make a Java2. > > Is that worthwhile? Well, there are discussions around null restriction > and a "flippening" there, classes being open for extension by default is > unideal, and hey while we're at it... > > There are many things that you might want to change. Some of these are > maybe worthwhile, some maybe not. All changes that make existing code no > longer compile need a really good justification. > > > switches have no breaks and fall throughs > > This one in particular can be achieved via addition, not subtraction. If > you don't want to use the switch with fallthrough, do not. > > > Is the effort on the compiler team too great? > > My outside read of the situation is that this is rarely the case. The > implied effort on the part of the wider ecosystem is the greater factor. > > > > On Sun, Jul 27, 2025 at 6:59?AM Aaryn Tonita wrote: > >> Since we are talking about deprecation, >> >> > But it would surely be better to just get to "switches are >> exhaustive". To do that, though, some existing code will stop compiling. >> >> > Now for an absurd statement. Can we deprecate the C-style switch? I >> understand why it cannot be done, no need to think of me as delusional, but >> can we at least send out an alert warning developers to avoid the old >> switch statement. >> >> Doesn't Java benefit more than other languages here? Rust recently moved >> forward with the idea of editions where legacy code would continue to >> compile with an older edition of the language. The compiler would still get >> better in time, (they wouldn't be stuck on an older compiler) and the code >> would be importable from newer editions. >> >> Why can't Java have something similar? The benefit Java has is that it >> targets the JVM (ok, rust targets LLVM IR) and an older edition can compile >> to the latest version of the bytecode if the compiler supported it. The >> language breaking features aren't necessarily JVM breakage. >> >> Old code could compile, developers could bugfix and update to latest >> compiler versions without breaking their existing code, but if they want to >> modernize their Java, then the code breaks but they have decided to put in >> the effort. >> >> I would love to have such a breaking change where implicit null is gone, >> where arrays require initialization, where switches have no breaks and fall >> throughs. Where my old code continues to compile on the latest compiler but >> on an older edition of the language. >> >> Is the effort on the compiler team too great? >> > > -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From johannes.spangenberg at hotmail.de Mon Jul 28 00:39:14 2025 From: johannes.spangenberg at hotmail.de (Johannes Spangenberg) Date: Mon, 28 Jul 2025 02:39:14 +0200 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <4c34513e-5f89-44bb-8836-cb0929f327c5@gmail.com> <2bff20ad-d905-4513-a647-b9a21d59f3bd@oracle.com> Message-ID: Just changing the behavior of switch would be problematic because it could silently change the behavior of the code. Not every developer who switches to a new version of the language reads all the release notes. It might also be tricky to find all places which would need to be adjusted. If some code did compile before, and it continues to compile now, it should not suddenly do something different. Anyway, you could of course still introduce an entirely new syntax and deprecate or even disable the old syntax. But that is kind of what happens with switch statements, except that the old syntax is not deprecated. At the end, it is balance. If you make too many changes too often, it can become annoying for people maintaining a large amount of code. It can also make it harder to google your problems as the answers may depend on the version of the language. As a result, it makes the language more complex as long as you haven't eliminated the old code from the ecosystem, which can take decades. I don't know what the right balance is. Historically, I think Java was rather successful by staying conservative. I remember having read a lot of backlash for the breaking changes in Java 17, however these changes were mostly in the JVM and not in the language. > The main reason to not introduce a "real" breaking change* (in Java or > in Rust) is to not fracture the ecosystem of libraries, with some > libraries only supporting the old version, others only supporting the > new version and libraries trying to support both at the same time > (relying on black magic). I think the topic was only about breaking the language, not the JVM. Old code should keep working as long as it is compiled against a previous language version (--release). > I'm not convinced that a "Java2"? hard break is a good idea. But for > the sake of argument suppose it was... Then [...] a smaller baby step > in that direction would be to define a set of the "best practices" > [...], and add a new lint warning flag I think Java should definitely consider deprecating old language features in the future. Otherwise, the language complexity will only grow over time. Such change in the ecosystem would take decades, but if new language features are added, designers should try if they can make old features obsolete eventually. Regards, Johannes From per-ake.minborg at oracle.com Mon Jul 28 07:20:47 2025 From: per-ake.minborg at oracle.com (Per-Ake Minborg) Date: Mon, 28 Jul 2025 07:20:47 +0000 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: <28312021.5047976.1753632484479.JavaMail.zimbra@univ-eiffel.fr> References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> <28312021.5047976.1753632484479.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hi David, Unrelated to arrays but to your "StrictCollection" sketch, I'd like to draw Stable Values to your attention where similar constructs are available. For example: var list = StableValue.list(5, i -> "List-" + i) Such lists might additionally benefit from certain performance optimizations (such as constant folding). Here is a video where I explain stable values in detail. Best, Per Minborg ________________________________ From: amber-dev on behalf of Remi Forax Sent: Sunday, July 27, 2025 6:08 PM To: Brian Goetz Cc: david Grajales ; amber-dev Subject: Re: Thoughts on Array Initialization in JavaONE 2025 ________________________________ From: "Brian Goetz" To: "david Grajales" , "amber-dev" Sent: Saturday, July 26, 2025 11:48:49 PM Subject: Re: Thoughts on Array Initialization in JavaONE 2025 All of the points you raise that "arrays are not the abstraction you are looking for" are absolutely true -- and well understood. The goal of improving array creation is not to help arrays win market share away from collections. But there is a reason that the language has arrays, and that reason hasn't gone away. Arrays are the bottom brick on which the tower of better data structures are built. You can't have ArrayList or HashMap without arrays. Arrays are part of the language for a reason. As we improve the language, sometimes arrays have to improve with it. (For example, if you have a non-implicitly-constructible value class NVA (one who has no valid default value), and someone wants to create an array of NVA![n], allowing the existing "zero the memory" array creation expression to create it would undermine the integrity of the runtime by exposing objects that are not in a valid state as determined by their constructor. So we can't allow that, which means we have to provide something else.) If we hadn't found the need to improve other aspects of initialization, we probably wouldn't have bothered to improve array initialization. But because we are improving initialization more broadly, we have to do the whole job. Not being able to create interesting arrays linguistically would forever look like a weird omission. Your suggestion -- "why not just" not improve array creation linguistically, and shunt any sort of exotic array creation to a privileged API -- leaves the user with little explanation for why the tower stands up. The bottom brick is not there, instead replaced by some sort of magic that seems to hold up the brick above it. While we expect relatively few programmers to program with arrays (ideally, just the guy who maintains ArrayList and HashMap, and the like), we should provide linguistic mechanisms for properly using core linguistic building blocks. I can imagine three implicit lines of thought for why you think such a low-level mechanism should be performed by a privileged library rather than a language feature: - The easier we make it to use, the more people will use it, and you would like fewer people to use it (as would we.) A scary-looking library will scare away more people than a pretty-looking language feature. - Language features are expensive, more expensive than libraries, so by shunting this to a library, we preserve resources to focus on more important things. - Array initialization appears to be competing for resources with features like collection literals, and you'd rather have the latter, so suggesting that we skip the former seems like it would bring the latter more quickly. These are appealing-sounding arguments, but they don't point to either usability wins or project-management wins. Arrays are the right tool for some jobs. Collections are the right tool for others (most others.) But the way to encourage people to use the right tool is not to make the other tools harder to use. (We too would like to have linguistic support for creating sets, lists, maps, etc, but that feature is not competing with arrays, its waiting for something else.) Nor is the cost of a privileged array-construction API significantly cheaper than a language feature. I always flip-flop between thinking that arrays are redeemable and losing all hope about them :) I think that the solution to our problem is to use value classes, after all, a value class allows abstraction without the runtime cost, right, so why not eating our own dog food ? Why not using array wrapped into a value class that implements the List interface ? By example, here is a List that allows only to access to an element of the List only if it has been initialized first (using a watermark), value class WatermarkedList implements List { E[] array; int watermark; // private constructor + static method WatermarkedList append(E element) { array[watermark] = element; return new WatermarkedList<>(array, watermark + 1); } E get(int index) { Objects.checkIndex(index, watermark); return array[index]; } int size() { return watermark; } WatermarkedList copyOf(int newCapacity) { ... } ... } Here the array can be initialized with zeroes (using a "JDK restricted" method) and a WatermarkedList is still safe to be used with element that are NVA. I think the JDK can define few of those lightweight Lists that can be used as primitive by anyone wanting to implement more complex data structures (ArrayList, HashMap, etc). Cheers, -Brian regards, R?mi On 7/26/2025 5:03 PM, david Grajales wrote: Dear Amber developers, I recently watched the JavaONE 2025 session titled ?A New Model for Java Object Initialization? and was particularly intrigued by the proposed improvements to array initialization. https://www.youtube.com/watch?v=XtvR4kqK8lo I strongly agree that Java needs better mechanisms for initializing data structures in a concise, expressive, and stricter manner?similar in spirit to Python?s list comprehensions and aligned with Strict initialization, required for Valhalla. Such constructs can help avoid subtle bugs and the presence of unintended null values. However, I remain skeptical about the decision to focus this new model exclusively around arrays. As has been discussed over the past few months, arrays are not ideal as a default abstraction, especially for students or in enterprise applications. Arrays are a low-level construct with several limitations: * They do not integrate well with generics. * They are of fixed size. * They lack methods and flexibility. * They are syntactically and semantically inconsistent with the rest of the Java Collections Framework. In many ways, arrays are a legacy feature inherited from C/C++?much like the original switch statement?that carry forward certain limitations that Java has otherwise worked hard to overcome. Given these issues, Why not just create an small API that facilitates the creation of the most used data structures with strict initialization? For example: void main(){ // toArray var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + i); IO.println("Array: " + Arrays.toString(array)); // toList var list = StrictCollections.toList(5, i -> "List-" + i); IO.println("List: " + list); // toSet var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); IO.println("Set: " + set); var map = StrictCollections.toMap( 5, i -> "Key-" + i, i -> i * 100 ); IO.println("Map: " + map); } public static class StrictCollections { public static T[] toArray(Class clazz, int size, IntFunction function) { @SuppressWarnings("unchecked") T[] array = (T[]) Array.newInstance(clazz, size); // This could be a frozen array once these are ready for (int i = 0; i < size; i++) { array[i] = function.apply(i); } return array; } public static ArrayList toList(int size, IntFunction function) { var list = new ArrayList(size); for (int i = 0; i < size; i++) { list.add(function.apply(i)); } return list; } public static HashSet toSet(int size, IntFunction function) { List list = new ArrayList<>(size); for (int i = 0; i < size; i++) { list.add(function.apply(i)); } return new HashSet<>(list); } public static HashMap toMap(int size, IntFunction kFunction, IntFunction vFunction) { HashMap map = new HashMap<>(size); for (int i = 0; i < size; i++) { map.put(kFunction.apply(i), vFunction.apply(i)); } return map; } } While this is admittedly a rough sketch developed in just a few minutes, I believe a similar?much more thoroughly designed?approach could provide much greater flexibility with far less complexity than introducing a dedicated array-specific feature. It would also extend naturally to a broader range of use cases --Such as being able to be combined with the Stream API in a much more ergonomic way--. Furthermore, as value classes and parametric JVM start to make it into the language and the JVM, the advantages of arrays and primitive types will diminish further. In that context, arrays will become even less compelling in the future. If Java is to introduce a safe, expressive, and idiomatic strict initialization literal for data structures, I would argue it should primarily support List, Set, and Map?especially Map, which remains one of the least ergonomic structures to initialize in the language today, particularly when compared to alternatives in Dart, Python, or even JavaScript objects. Data structures that are much more used. Thank you so much for all your work and always yours -------------- next part -------------- An HTML attachment was scrubbed... URL: From atonita at proton.me Mon Jul 28 07:36:32 2025 From: atonita at proton.me (Aaryn Tonita) Date: Mon, 28 Jul 2025 07:36:32 +0000 Subject: Behavior of Switch Statements without fallthrough In-Reply-To: References: <2bff20ad-d905-4513-a647-b9a21d59f3bd@oracle.com> Message-ID: > "why don't we get rid of all the 'mistakes' and make a Java 2" Indeed, this is exactly what I wanted to bring up, because unlike > Python 2/Python 3 is a good example of what happen if you introduce a breaking change where importing a dependency written in python 2 was generally impossible for the python 3 interpreter, if the breaking change only existed in the Java language the JVM bytecode could save the day and make code interoperable. Rust avoided this by marking crates with the edition and promising to keep compiling old editions and python chose a hard break. Java can avoid it simply by not making breaking changes to the JVM. In practice, > add a new lint warning flag -Xlint:modern-java that would warn about any non-compliant usage. is what is already done but in a fractured and lacklustre manner with additional tools. Static linters add a side channel type checker to analyze null flows using type annotations. Static linters can also forbid usage of dangerous features like switch fallthroughs. But enabling these tools generally requires some maintenance and diligence that is often delayed because it does not come out of the box with javac. As a developer that enjoys the Java language I don't think of this as a canard so much as a hope. If Java2 can only ever exist as a language with a combination of the Java language itself plus an ad hoc selection of static analysers then other languages with a more out of the box experience become attractive. I see this a little bit in the same grain as the moves towards "paving the onramp": I would love to have a batteries included static analyser or have it directly built into the type system without needing to invest the effort to choose and arrange multiple tools. So having an Oracle/OpenJDK linter would be also great. On the other hand static analysers are becoming ubiquitous enough that perhaps it is even a basic thing that would be included in every project soon enough. I also can see the social aspect that this kind of backwards compatibility is still a hard break for businesses that would need to "modernise" code that works using features now considered "bad practice"; certainly there is limited patience for that. From atonita at proton.me Mon Jul 28 08:08:40 2025 From: atonita at proton.me (Aaryn Tonita) Date: Mon, 28 Jul 2025 08:08:40 +0000 Subject: Bare/method pattern bindings Message-ID: In my organization we have settled upon an architecture that leverages sealed interfaces with records implementing those interfaces to build up our domain model. The sealed interfaces enable the needed level of polymorphism and the immutable records with canonical constructors ensure that our business invariants are clear and easily enforced. When transitioning between various states (the implementing records) we can easily switch on the instance of a sealed interface and pattern match the records to easily build the next state. We also similarly use the design when mapping to DTO's or database entities. A benefit of the pattern matching approach here arises on iteration of the design. As we add features to the application, we will add additional fields to the records and the deconstruction sites need to be updated with the new field. Unlike with JavaBeans, it doesn't happen that we fail to update such a state transition or mapping and create a bug by forgetting to carryover the new field: you cannot compile the code until you add the field to the record deconstruction. It can happen that the field gets marked as ignored (with the _ pattern) generally with a comment. A nuisance arises however when you want to deconstruct an instance of a record instead of a instance of a sealed interface because patterns are only available in case arms and with instanceof. The nuisance means that you end up with code such as: public class PatternDeconstruction { record Foo() {} record Bar() {} record FooBar(Foo foo, Bar bar) {} record OtherFooBar(Foo foo, Bar bar) {} interface FooBarSink { void sink(Foo foo); void sink(Bar bar); } OtherFooBar map(FooBar fooBar) { Objects.requireNonNull(fooBar); if (fooBar instanceof FooBar(var foo, var bar)) { return new OtherFooBar(foo, bar); } else { throw new AssertionError("Unreachable."); } } OtherFooBar map2(FooBar fooBar) { return switch (fooBar) { case FooBar(var foo, var bar) -> new OtherFooBar(foo, bar); }; } void sink(FooBarSink sink, FooBar fooBar) { Objects.requireNonNull(fooBar); if (fooBar instanceof FooBar(var foo, var bar)) { sink.sink(foo); sink.sink(bar); } }} A choice must be made between giving up on the deconstruction or a choice between an if or a switch. The if with instanceof is especially ugly because of the "unreachable" (null guarding) branch. This doesn't occur on a sink type method, it just confusingly looks like the branch might not always trigger. The switch instead often creates two levels of indentation (not shown here). However, in all cases static analysers complain about this code because it is never conditional. I was hoping there would be JEP for a bare pattern finding or a method parameter pattern binding, something that would allow one of OtherFooBar map3(FooBar fooBar) { FooBar(var foo, var bar) = fooBar; return new OtherFooBar(foo, bar); } OtherFooBar map4(FooBar(var foo, var bar)) { return new OtherFooBar(foo, bar); } but such a JEP doesn't seem to exist. It feels natural to me that such a feature should be present but I am unsure if my intuition is coming from my pattern matching experience in other languages or if any Java developer would naturally share the intuition. In any case, I am hoping you have such a feature on the radar, but I am aware of the derived record creation and would certainly vote for prioritizing that just to give you some anecdata on the practical impacts of the workarounds between the two. We are eagerly awaiting the derived record creation. -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Mon Jul 28 08:43:36 2025 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Mon, 28 Jul 2025 08:43:36 +0000 Subject: Bare/method pattern bindings In-Reply-To: References: Message-ID: Thanks for your email. An instanceof statement/pattern-let statement is firmly on our roadmap (i.e. the first solution you suggest). Gavin On 28 Jul 2025, at 09:08, Aaryn Tonita wrote: In my organization we have settled upon an architecture that leverages sealed interfaces with records implementing those interfaces to build up our domain model. The sealed interfaces enable the needed level of polymorphism and the immutable records with canonical constructors ensure that our business invariants are clear and easily enforced. When transitioning between various states (the implementing records) we can easily switch on the instance of a sealed interface and pattern match the records to easily build the next state. We also similarly use the design when mapping to DTO's or database entities. A benefit of the pattern matching approach here arises on iteration of the design. As we add features to the application, we will add additional fields to the records and the deconstruction sites need to be updated with the new field. Unlike with JavaBeans, it doesn't happen that we fail to update such a state transition or mapping and create a bug by forgetting to carryover the new field: you cannot compile the code until you add the field to the record deconstruction. It can happen that the field gets marked as ignored (with the _ pattern) generally with a comment. A nuisance arises however when you want to deconstruct an instance of a record instead of a instance of a sealed interface because patterns are only available in case arms and with instanceof. The nuisance means that you end up with code such as: public class PatternDeconstruction { record Foo() {} record Bar() {} record FooBar(Foo foo, Bar bar) {} record OtherFooBar(Foo foo, Bar bar) {} interface FooBarSink { void sink(Foo foo); void sink(Bar bar); } OtherFooBar map(FooBar fooBar) { Objects.requireNonNull(fooBar); if (fooBar instanceof FooBar(var foo, var bar)) { return new OtherFooBar(foo, bar); } else { throw new AssertionError("Unreachable."); } } OtherFooBar map2(FooBar fooBar) { return switch (fooBar) { case FooBar(var foo, var bar) -> new OtherFooBar(foo, bar); }; } void sink(FooBarSink sink, FooBar fooBar) { Objects.requireNonNull(fooBar); if (fooBar instanceof FooBar(var foo, var bar)) { sink.sink(foo); sink.sink(bar); } } } A choice must be made between giving up on the deconstruction or a choice between an if or a switch. The if with instanceof is especially ugly because of the "unreachable" (null guarding) branch. This doesn't occur on a sink type method, it just confusingly looks like the branch might not always trigger. The switch instead often creates two levels of indentation (not shown here). However, in all cases static analysers complain about this code because it is never conditional. I was hoping there would be JEP for a bare pattern finding or a method parameter pattern binding, something that would allow one of OtherFooBar map3(FooBar fooBar) { FooBar(var foo, var bar) = fooBar; return new OtherFooBar(foo, bar); } OtherFooBar map4(FooBar(var foo, var bar)) { return new OtherFooBar(foo, bar); } but such a JEP doesn't seem to exist. It feels natural to me that such a feature should be present but I am unsure if my intuition is coming from my pattern matching experience in other languages or if any Java developer would naturally share the intuition. In any case, I am hoping you have such a feature on the radar, but I am aware of the derived record creation and would certainly vote for prioritizing that just to give you some anecdata on the practical impacts of the workarounds between the two. We are eagerly awaiting the derived record creation. -------------- next part -------------- An HTML attachment was scrubbed... URL: From david.1993grajales at gmail.com Mon Jul 28 16:57:36 2025 From: david.1993grajales at gmail.com (david Grajales) Date: Mon, 28 Jul 2025 11:57:36 -0500 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> <28312021.5047976.1753632484479.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hi Mr. Per Minborg Thanks for the advice, I had already watched the presentation (excellent btw) but I haven't had the time to properly play around with this new API. I promise I will give it a check ASAP. Cheers. El lun, 28 jul 2025 a la(s) 2:21?a.m., Per-Ake Minborg ( per-ake.minborg at oracle.com) escribi?: > Hi David, > > Unrelated to arrays but to your "StrictCollection" sketch, I'd like to > draw Stable Values to your attention where > similar constructs are available. > > For example: > > var list = StableValue.list(5, i -> "List-" + i) > > Such lists might additionally benefit from certain performance > optimizations (such as constant folding). Here is a video > where I explain > stable values in detail. > > > Best, Per Minborg > ------------------------------ > *From:* amber-dev on behalf of Remi Forax < > forax at univ-mlv.fr> > *Sent:* Sunday, July 27, 2025 6:08 PM > *To:* Brian Goetz > *Cc:* david Grajales ; amber-dev < > amber-dev at openjdk.org> > *Subject:* Re: Thoughts on Array Initialization in JavaONE 2025 > > > > ------------------------------ > > *From: *"Brian Goetz" > *To: *"david Grajales" , "amber-dev" < > amber-dev at openjdk.org> > *Sent: *Saturday, July 26, 2025 11:48:49 PM > *Subject: *Re: Thoughts on Array Initialization in JavaONE 2025 > > All of the points you raise that "arrays are not the abstraction you are > looking for" are absolutely true -- and well understood. The goal of > improving array creation is not to help arrays win market share away from > collections. > > But there is a reason that the language has arrays, and that reason hasn't > gone away. Arrays are the bottom brick on which the tower of better data > structures are built. You can't have ArrayList or HashMap without arrays. > Arrays are part of the language for a reason. As we improve the language, > sometimes arrays have to improve with it. (For example, if you have a > non-implicitly-constructible value class NVA (one who has no valid default > value), and someone wants to create an array of NVA![n], allowing the > existing "zero the memory" array creation expression to create it would > undermine the integrity of the runtime by exposing objects that are not in > a valid state as determined by their constructor. So we can't allow that, > which means we have to provide something else.) > > If we hadn't found the need to improve other aspects of initialization, we > probably wouldn't have bothered to improve array initialization. But > because we are improving initialization more broadly, we have to do the > whole job. Not being able to create interesting arrays linguistically > would forever look like a weird omission. > > Your suggestion -- "why not just" not improve array creation > linguistically, and shunt any sort of exotic array creation to a privileged > API -- leaves the user with little explanation for why the tower stands > up. The bottom brick is not there, instead replaced by some sort of magic > that seems to hold up the brick above it. While we expect relatively few > programmers to program with arrays (ideally, just the guy who maintains > ArrayList and HashMap, and the like), we should provide linguistic > mechanisms for properly using core linguistic building blocks. > > I can imagine three implicit lines of thought for why you think such a > low-level mechanism should be performed by a privileged library rather than > a language feature: > > - The easier we make it to use, the more people will use it, and you > would like fewer people to use it (as would we.) A scary-looking library > will scare away more people than a pretty-looking language feature. > - Language features are expensive, more expensive than libraries, so by > shunting this to a library, we preserve resources to focus on more > important things. > - Array initialization appears to be competing for resources with > features like collection literals, and you'd rather have the latter, so > suggesting that we skip the former seems like it would bring the latter > more quickly. > > These are appealing-sounding arguments, but they don't point to either > usability wins or project-management wins. Arrays are the right tool for > some jobs. Collections are the right tool for others (most others.) But > the way to encourage people to use the right tool is not to make the other > tools harder to use. (We too would like to have linguistic support for > creating sets, lists, maps, etc, but that feature is not competing with > arrays, its waiting for something else.) Nor is the cost of a privileged > array-construction API significantly cheaper than a language feature. > > > I always flip-flop between thinking that arrays are redeemable and losing > all hope about them :) > > I think that the solution to our problem is to use value classes, after > all, a value class allows abstraction without the runtime cost, right, so > why not eating our own dog food ? > > Why not using array wrapped into a value class that implements the List > interface ? > > By example, here is a List that allows only to access to an element of the > List only if it has been initialized first (using a watermark), > > value class WatermarkedList implements List { > E[] array; > int watermark; > > // private constructor + static method > > WatermarkedList append(E element) { > array[watermark] = element; > return new WatermarkedList<>(array, watermark + 1); > } > > E get(int index) { > Objects.checkIndex(index, watermark); > return array[index]; > } > > int size() { return watermark; } > > WatermarkedList copyOf(int newCapacity) { ... } > > ... > } > > Here the array can be initialized with zeroes (using a "JDK restricted" > method) and a WatermarkedList is still safe to be used with element that > are NVA. > > I think the JDK can define few of those lightweight Lists that can be used > as primitive by anyone wanting to implement more complex data structures > (ArrayList, HashMap, etc). > > > > Cheers, > -Brian > > > > regards, > R?mi > > > > > > > > > On 7/26/2025 5:03 PM, david Grajales wrote: > > Dear Amber developers, > > I recently watched the JavaONE 2025 session titled *?A New Model for Java > Object Initialization?* and was particularly intrigued by the proposed > improvements to array initialization. > > https://www.youtube.com/watch?v=XtvR4kqK8lo > > > I strongly agree that Java needs better mechanisms for initializing data > structures in a concise, expressive, and stricter manner?similar in spirit > to Python?s list comprehensions and aligned with Strict initialization, > required for Valhalla. Such constructs can help avoid subtle bugs and the > presence of unintended null values. However, I remain skeptical about the > decision to focus this new model exclusively around arrays. > > As has been discussed over the past few months, arrays are not ideal as a > default abstraction, especially for students or in enterprise applications. > Arrays are a low-level construct with several limitations: > > - > > They do not integrate well with generics. > - > > They are of fixed size. > - > > They lack methods and flexibility. > - > > They are syntactically and semantically inconsistent with the rest of > the Java Collections Framework. > > In many ways, arrays are a legacy feature inherited from C/C++?much like > the original switch statement?that carry forward certain limitations that > Java has otherwise worked hard to overcome. > > Given these issues, Why not just create an small API that facilitates the > creation of the most used data structures with strict initialization? > > For example: > > > void main(){ > > > // toArray > > var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + > i); > > IO.println("Array: " + Arrays.toString(array)); > > > // toList > > var list = StrictCollections.toList(5, i -> "List-" + i); > > IO.println("List: " + list); > > > // toSet > > var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); > > IO.println("Set: " + set); > > > > var map = StrictCollections.toMap( > > 5, > > i -> "Key-" + i, > > i -> i * 100 > > ); > > IO.println("Map: " + map); > > > > > } > > > > public static class StrictCollections { > > > public static T[] toArray(Class clazz, int size, IntFunction > function) { > > @SuppressWarnings("unchecked") > > T[] array = (T[]) Array.newInstance(clazz, size); // This could be > a frozen array once these are ready > > for (int i = 0; i < size; i++) { > > array[i] = function.apply(i); > > } > > return array; > > } > > > public static ArrayList toList(int size, IntFunction > function) { > > var list = new ArrayList(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return list; > > } > > > public static HashSet toSet(int size, IntFunction function) { > > List list = new ArrayList<>(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return new HashSet<>(list); > > } > > > public static HashMap toMap(int size, IntFunction > kFunction, IntFunction vFunction) { > > HashMap map = new HashMap<>(size); > > for (int i = 0; i < size; i++) { > > map.put(kFunction.apply(i), vFunction.apply(i)); > > } > > return map; > > } > > } > > While this is admittedly a rough sketch developed in just a few minutes, I > believe a similar?much more thoroughly designed?approach could provide much > greater flexibility with far less complexity than introducing a dedicated > array-specific feature. It would also extend naturally to a broader range > of use cases --Such as being able to be combined with the Stream API in a > much more ergonomic way--. Furthermore, as value classes and parametric JVM > start to make it into the language and the JVM, the advantages of arrays > and primitive types will diminish further. In that context, arrays will > become even less compelling in the future. > > If Java is to introduce a safe, expressive, and idiomatic strict > initialization literal for data structures, I would argue it should > primarily support List, Set, and Map?especially Map, which remains one of > the least ergonomic structures to initialize in the language today, > particularly when compared to alternatives in Dart, Python, or even > JavaScript objects. Data structures that are much more used. > > > Thank you so much for all your work and always yours > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From rob.ross at gmail.com Mon Jul 28 21:24:01 2025 From: rob.ross at gmail.com (Rob Ross) Date: Mon, 28 Jul 2025 14:24:01 -0700 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> Message-ID: In Python, arrays exist as a lower level library or via third-party libraries like NumPy. Unless you're doing specialized processing, you don't typically work with actually arrays. As with Java, you're normally working with lists. But the syntax in Python for working with lists makes list initialization simple and easy. I would love to see a similar syntax in Java for both List and Map initialization. E.g., ```Python foo = [{"key": {"subkey": "value"}}] ``` The simplest way I can duplicate this in Java is ```Java List> foo = List.of( Map.of("key", Map.of("subkey", "value")) ); ``` Now, this doesn't look too bad. In Java this has created an immutable List, which is probably adequte in many cases. In the context of the actual code as a unit test, immutability is fine; but if you needed mutability: List> foo = new ArrayList<>(); Map outerMap = new HashMap<>(); Map innerMap = new HashMap<>(); innerMap.put("subkey", "value"); outerMap.put("key", innerMap); foo.add(outerMap); And you can see how the boilerplate starts to obscure the nature of the data for more complicated initializations: Python: result [{"key": {"subkey": [{"subsubkey": [{"subsubsubkey": [{"subsubsubsubkey": [1]}]}]}]}}] Java: List> result = List.of( Map.of( "key", Map.of( "subkey", List.of( Map.of( "subsubkey", List.of( Map.of( "subsubsubkey", List.of( Map.of( "subsubsubsubkey", List.of(1) ) ) ) ) ) ) ) ) ); So it would be nice if Java could use [] and {} as syntax for initializing Lists and Maps. I don't think it would be too complicated to add this syntax, e.g., List foo = [1, 2, 3]; // clear in context this is initializing a List, not an array. or more explicitly: List foo = new ArrayList<>[1, 2, 3]; or perhaps List foo = new ArrayList<>([1, 2, 3]); // and [1,2,3] could be auto-boxed to a Collection object for the existing ArrayList constructor. I'm just talking about initialization syntax. The compiler should be able to determine the new syntax from context, just as it can tell the difference in {} between a block of code and an array initializer or anonymous class definition. I also could be totally wrong on how "easy" it would be to add this. But I do know it would simplify my unit testing code! - Rob On Sat, Jul 26, 2025 at 2:49?PM Brian Goetz wrote: > All of the points you raise that "arrays are not the abstraction you are > looking for" are absolutely true -- and well understood. The goal of > improving array creation is not to help arrays win market share away from > collections. > > But there is a reason that the language has arrays, and that reason hasn't > gone away. Arrays are the bottom brick on which the tower of better data > structures are built. You can't have ArrayList or HashMap without arrays. > Arrays are part of the language for a reason. As we improve the language, > sometimes arrays have to improve with it. (For example, if you have a > non-implicitly-constructible value class NVA (one who has no valid default > value), and someone wants to create an array of NVA![n], allowing the > existing "zero the memory" array creation expression to create it would > undermine the integrity of the runtime by exposing objects that are not in > a valid state as determined by their constructor. So we can't allow that, > which means we have to provide something else.) > > If we hadn't found the need to improve other aspects of initialization, we > probably wouldn't have bothered to improve array initialization. But > because we are improving initialization more broadly, we have to do the > whole job. Not being able to create interesting arrays linguistically > would forever look like a weird omission. > > Your suggestion -- "why not just" not improve array creation > linguistically, and shunt any sort of exotic array creation to a privileged > API -- leaves the user with little explanation for why the tower stands > up. The bottom brick is not there, instead replaced by some sort of magic > that seems to hold up the brick above it. While we expect relatively few > programmers to program with arrays (ideally, just the guy who maintains > ArrayList and HashMap, and the like), we should provide linguistic > mechanisms for properly using core linguistic building blocks. > > I can imagine three implicit lines of thought for why you think such a > low-level mechanism should be performed by a privileged library rather than > a language feature: > > - The easier we make it to use, the more people will use it, and you > would like fewer people to use it (as would we.) A scary-looking library > will scare away more people than a pretty-looking language feature. > - Language features are expensive, more expensive than libraries, so by > shunting this to a library, we preserve resources to focus on more > important things. > - Array initialization appears to be competing for resources with > features like collection literals, and you'd rather have the latter, so > suggesting that we skip the former seems like it would bring the latter > more quickly. > > These are appealing-sounding arguments, but they don't point to either > usability wins or project-management wins. Arrays are the right tool for > some jobs. Collections are the right tool for others (most others.) But > the way to encourage people to use the right tool is not to make the other > tools harder to use. (We too would like to have linguistic support for > creating sets, lists, maps, etc, but that feature is not competing with > arrays, its waiting for something else.) Nor is the cost of a privileged > array-construction API significantly cheaper than a language feature. > > Cheers, > -Brian > > > > > > > > > > On 7/26/2025 5:03 PM, david Grajales wrote: > > Dear Amber developers, > > I recently watched the JavaONE 2025 session titled *?A New Model for Java > Object Initialization?* and was particularly intrigued by the proposed > improvements to array initialization. > > https://www.youtube.com/watch?v=XtvR4kqK8lo > > > I strongly agree that Java needs better mechanisms for initializing data > structures in a concise, expressive, and stricter manner?similar in spirit > to Python?s list comprehensions and aligned with Strict initialization, > required for Valhalla. Such constructs can help avoid subtle bugs and the > presence of unintended null values. However, I remain skeptical about the > decision to focus this new model exclusively around arrays. > > As has been discussed over the past few months, arrays are not ideal as a > default abstraction, especially for students or in enterprise applications. > Arrays are a low-level construct with several limitations: > > - > > They do not integrate well with generics. > - > > They are of fixed size. > - > > They lack methods and flexibility. > - > > They are syntactically and semantically inconsistent with the rest of > the Java Collections Framework. > > In many ways, arrays are a legacy feature inherited from C/C++?much like > the original switch statement?that carry forward certain limitations that > Java has otherwise worked hard to overcome. > > Given these issues, Why not just create an small API that facilitates the > creation of the most used data structures with strict initialization? > > For example: > > > void main(){ > > > // toArray > > var array = StrictCollections.toArray(String.class, 5, i -> "Item-" + > i); > > IO.println("Array: " + Arrays.toString(array)); > > > // toList > > var list = StrictCollections.toList(5, i -> "List-" + i); > > IO.println("List: " + list); > > > // toSet > > var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); > > IO.println("Set: " + set); > > > > var map = StrictCollections.toMap( > > 5, > > i -> "Key-" + i, > > i -> i * 100 > > ); > > IO.println("Map: " + map); > > > > > } > > > > public static class StrictCollections { > > > public static T[] toArray(Class clazz, int size, IntFunction > function) { > > @SuppressWarnings("unchecked") > > T[] array = (T[]) Array.newInstance(clazz, size); // This could be > a frozen array once these are ready > > for (int i = 0; i < size; i++) { > > array[i] = function.apply(i); > > } > > return array; > > } > > > public static ArrayList toList(int size, IntFunction > function) { > > var list = new ArrayList(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return list; > > } > > > public static HashSet toSet(int size, IntFunction function) { > > List list = new ArrayList<>(size); > > for (int i = 0; i < size; i++) { > > list.add(function.apply(i)); > > } > > return new HashSet<>(list); > > } > > > public static HashMap toMap(int size, IntFunction > kFunction, IntFunction vFunction) { > > HashMap map = new HashMap<>(size); > > for (int i = 0; i < size; i++) { > > map.put(kFunction.apply(i), vFunction.apply(i)); > > } > > return map; > > } > > } > > While this is admittedly a rough sketch developed in just a few minutes, I > believe a similar?much more thoroughly designed?approach could provide much > greater flexibility with far less complexity than introducing a dedicated > array-specific feature. It would also extend naturally to a broader range > of use cases --Such as being able to be combined with the Stream API in a > much more ergonomic way--. Furthermore, as value classes and parametric JVM > start to make it into the language and the JVM, the advantages of arrays > and primitive types will diminish further. In that context, arrays will > become even less compelling in the future. > > If Java is to introduce a safe, expressive, and idiomatic strict > initialization literal for data structures, I would argue it should > primarily support List, Set, and Map?especially Map, which remains one of > the least ergonomic structures to initialize in the language today, > particularly when compared to alternatives in Dart, Python, or even > JavaScript objects. Data structures that are much more used. > > > Thank you so much for all your work and always yours > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jul 28 21:30:51 2025 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 28 Jul 2025 17:30:51 -0400 Subject: Thoughts on Array Initialization in JavaONE 2025 In-Reply-To: References: <301f45f7-670b-4703-9f08-11bb256b2ed9@oracle.com> Message-ID: <5c99f7df-b0db-4fc9-83c6-867affb9ab05@oracle.com> This is the feature we sometimes refer to as "Collection Literals" or "Structured Literals".? It is on the roadmap, but there are some other things ahead of it. (There was a poor proposal back in the Project Coin days for this feature, which was thankfully rejected.) (And, for fans of pattern matching, the dual of "structured literal" is "structured pattern".) On 7/28/2025 5:24 PM, Rob Ross wrote: > In Python, arrays exist as a lower level library or via third-party > libraries like NumPy. Unless you're doing specialized processing, you > don't typically work with actually arrays. As with Java, you're > normally working with lists. > But the syntax in Python for working with lists makes list > initialization simple and easy. I would love to see a similar syntax > in Java for both List and Map initialization. > E.g., > ```Python > foo = [{"key": {"subkey": "value"}}] > ``` > The simplest way I can duplicate this in Java is > ```Java > List> foo = List.of( > ? ? Map.of("key", Map.of("subkey", "value")) > ); > ``` > Now, this doesn't look too bad. In Java this has created an immutable > List, which is probably adequte in many cases. In the context of the > actual code as a unit test, immutability is fine; but if you needed > mutability: > List> foo = new ArrayList<>(); > Map outerMap = new HashMap<>(); > Map innerMap = new HashMap<>(); > > innerMap.put("subkey", "value"); > outerMap.put("key", innerMap); > foo.add(outerMap); > > And you can see how the boilerplate starts to obscure the nature of > the data for more complicated initializations: > Python: > result [{"key": {"subkey": [{"subsubkey": [{"subsubsubkey": > [{"subsubsubsubkey": [1]}]}]}]}}] > > Java: > List> result = List.of( > ? ? Map.of( > ? ? ? ? "key", Map.of( > ? ? ? ? ? ? "subkey", List.of( > ? ? ? ? ? ? ? ? Map.of( > ? ? ? ? ? ? ? ? ? ? "subsubkey", List.of( > ? ? ? ? ? ? ? ? ? ? ? ? Map.of( > ? ? ? ? ? ? ? ? ? ? ? ? ? ? "subsubsubkey", List.of( > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? Map.of( > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "subsubsubsubkey", List.of(1) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ) > ? ? ? ? ? ? ? ? ? ? ? ? ) > ? ? ? ? ? ? ? ? ? ? ) > ? ? ? ? ? ? ? ? ) > ? ? ? ? ? ? ) > ? ? ? ? ) > ? ? ) > ); > > So it would be nice if Java could use [] and {} as syntax for > initializing Lists and Maps. I don't think it would be too complicated > to add this syntax, e.g., > > List foo = [1, 2, 3]; // clear in context this is > initializing a List, not an array. > > or more explicitly: > List foo = new ArrayList<>[1, 2, 3]; > > or perhaps > List foo = new ArrayList<>([1, 2, 3]); // and [1,2,3] could > be auto-boxed to a Collection object for the existing ArrayList > constructor. > > I'm just talking about initialization syntax. The compiler should be > able to determine the new syntax from context, just as it can tell the > difference in {} between a block of code and an array initializer or > anonymous class definition. > > I also could be totally wrong on how "easy" it would be to add this. > But I do know it would simplify my unit testing code! > > - Rob > > > > > On Sat, Jul 26, 2025 at 2:49?PM Brian Goetz > wrote: > > All of the points you raise that "arrays are not the abstraction > you are looking for" are absolutely true -- and well understood. > The goal of improving array creation is not to help arrays win > market share away from collections. > > But there is a reason that the language has arrays, and that > reason hasn't gone away.? Arrays are the bottom brick on which the > tower of better data structures are built.? You can't have > ArrayList or HashMap without arrays.? Arrays are part of the > language for a reason.? As we improve the language, sometimes > arrays have to improve with it.? (For example, if you have a > non-implicitly-constructible value class NVA (one who has no valid > default value), and someone wants to create an array of NVA![n], > allowing the existing "zero the memory" array creation expression > to create it would undermine the integrity of the runtime by > exposing objects that are not in a valid state as determined by > their constructor.? So we can't allow that, which means we have to > provide something else.) > > If we hadn't found the need to improve other aspects of > initialization, we probably wouldn't have bothered to improve > array initialization.? But because we are improving initialization > more broadly, we have to do the whole job. Not being able to > create interesting arrays linguistically would forever look like a > weird omission. > > Your suggestion -- "why not just" not improve array creation > linguistically, and shunt any sort of exotic array creation to a > privileged API -- leaves the user with little explanation for why > the tower stands up.? The bottom brick is not there, instead > replaced by some sort of magic that seems to hold up the brick > above it.? While we expect relatively few programmers to program > with arrays (ideally, just the guy who maintains ArrayList and > HashMap, and the like), we should provide linguistic mechanisms > for properly using core linguistic building blocks. > > I can imagine three implicit lines of thought for why you think > such a low-level mechanism should be performed by a privileged > library rather than a language feature: > > ?- The easier we make it to use, the more people will use it, and > you would like fewer people to use it (as would we.)? A > scary-looking library will scare away more people than a > pretty-looking language feature. > ?- Language features are expensive, more expensive than libraries, > so by shunting this to a library, we preserve resources to focus > on more important things. > ?- Array initialization appears to be competing for resources with > features like collection literals, and you'd rather have the > latter, so suggesting that we skip the former seems like it would > bring the latter more quickly. > > These are appealing-sounding arguments, but they don't point to > either usability wins or project-management wins.? Arrays are the > right tool for some jobs.? Collections are the right tool for > others (most others.)? But the way to encourage people to use the > right tool is not to make the other tools harder to use.? (We too > would like to have linguistic support for creating sets, lists, > maps, etc, but that feature is not competing with arrays, its > waiting for something else.)? Nor is the cost of a privileged > array-construction API significantly cheaper than a language feature. > > Cheers, > -Brian > > > > > > > > > > On 7/26/2025 5:03 PM, david Grajales wrote: >> >> Dear Amber developers, >> >> I recently watched the JavaONE 2025 session titled /?A New Model >> for Java Object Initialization?/?and was particularly intrigued >> by the proposed improvements to array initialization. >> >> https://www.youtube.com/watch?v=XtvR4kqK8lo >> >> >> >> I strongly agree that Java needs better mechanisms for >> initializing data structures in a concise, expressive, and >> stricter manner?similar in spirit to Python?s list comprehensions >> and aligned with Strict initialization, required for Valhalla. >> Such constructs can help avoid subtle bugs and the presence of >> unintended |null|?values. However, I remain skeptical about the >> decision to focus this new model exclusively around arrays. >> >> As has been discussed over the past few months, arrays are not >> ideal as a default abstraction, especially for students or in >> enterprise applications. Arrays are a low-level construct with >> several limitations: >> >> * >> >> They do not integrate well with generics. >> >> * >> >> They are of fixed size. >> >> * >> >> They lack methods and flexibility. >> >> * >> >> They are syntactically and semantically inconsistent with the >> rest of the Java Collections Framework. >> >> In many ways, arrays are a legacy feature inherited from >> C/C++?much like the original |switch|?statement?that carry >> forward certain limitations that Java has otherwise worked hard >> to overcome. >> >> Given these issues, Why not just create an small API that >> facilitates the creation of the most used data structures with >> strict initialization? >> >> For example: >> >> >> void main(){ >> >> >> ? ? // toArray >> >> ? ? var array = StrictCollections.toArray(String.class, 5, i -> >> "Item-" + i); >> >> ? ? IO.println("Array: " + Arrays.toString(array)); >> >> >> ? ? // toList >> >> ? ? var list = StrictCollections.toList(5, i -> "List-" + i); >> >> ? ? IO.println("List: " + list); >> >> >> ? ? // toSet >> >> ? ? var set = StrictCollections.toSet(5, i -> "Set-" + (i % 3)); >> >> ? ? IO.println("Set: " + set); >> >> >> >> ? ? var map = StrictCollections.toMap( >> >> ? ? ? ? 5, >> >> ? ? ? ? i -> "Key-" + i, >> >> ? ? ? ? i -> i * 100 >> >> ? ? ); >> >> ? ? IO.println("Map: " + map); >> >> >> } >> >> >> >> public static class StrictCollections { >> >> >> ? ? public static T[] toArray(Class clazz, int size, >> IntFunction function) { >> >> ? ? ? ? @SuppressWarnings("unchecked") >> >> ? ? ? ? T[] array = (T[]) Array.newInstance(clazz, size); // This >> could be a frozen array once these are ready >> >> ? ? ? ? for (int i = 0; i < size; i++) { >> >> ? ? ? ? ? ? array[i] = function.apply(i); >> >> ? ? ? ? } >> >> ? ? ? ? return array; >> >> ? ? } >> >> >> ? ? public static ArrayList toList(int size, >> IntFunction function) { >> >> ? ? ? ? var list = new ArrayList(size); >> >> ? ? ? ? for (int i = 0; i < size; i++) { >> >> ? ? ? ? ? ? list.add(function.apply(i)); >> >> ? ? ? ? } >> >> ? ? ? ? return list; >> >> ? ? } >> >> >> ? ? public static HashSet toSet(int size, IntFunction >> function) { >> >> ? ? ? ? List list = new ArrayList<>(size); >> >> ? ? ? ? for (int i = 0; i < size; i++) { >> >> ? ? ? ? ? ? list.add(function.apply(i)); >> >> ? ? ? ? } >> >> ? ? ? ? return new HashSet<>(list); >> >> ? ? } >> >> >> ? ? public static HashMap toMap(int size, >> IntFunction kFunction, IntFunction vFunction) { >> >> ? ? ? ? HashMap map = new HashMap<>(size); >> >> ? ? ? ? for (int i = 0; i < size; i++) { >> >> ? ? ? ? ? ? map.put(kFunction.apply(i), vFunction.apply(i)); >> >> ? ? ? ? } >> >> ? ? ? ? return map; >> >> ? ? } >> >> } >> >> While this is admittedly a rough sketch developed in just a few >> minutes, I believe a similar?much more thoroughly >> designed?approach could provide much greater flexibility with far >> less complexity than introducing a dedicated array-specific >> feature. It would also extend naturally to a broader range of use >> cases --Such as being able to be combined with the Stream API in >> a much more ergonomic way--. Furthermore, as value classes and >> parametric JVM start to make it into the language and the JVM, >> the advantages of arrays and primitive types will diminish >> further. In that context, arrays will become even less compelling >> in the future. >> >> If Java is to introduce a safe, expressive, and idiomatic strict >> initialization literal for data structures, I would argue it >> should primarily support |List|, |Set|, and |Map|?especially >> |Map|, which remains one of the least ergonomic structures to >> initialize in the language today, particularly when compared to >> alternatives in Dart, Python, or even JavaScript objects. Data >> structures that are much more used. >> >> >> Thank you so much for all your work and always yours >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: