From mark.reinhold at oracle.com Wed Nov 1 17:58:47 2023 From: mark.reinhold at oracle.com (Mark Reinhold) Date: Wed, 1 Nov 2023 17:58:47 +0000 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) Message-ID: <20231101175845.9702264CBD7@eggemoggin.niobe.net> https://openjdk.org/jeps/463 Summary: Evolve the Java programming language so that students can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, students can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. This is a preview language feature. - Mark From james.laskey at oracle.com Wed Nov 1 18:14:07 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Wed, 1 Nov 2023 18:14:07 +0000 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: <20231101175845.9702264CBD7@eggemoggin.niobe.net> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: Thank you Mark. > On Nov 1, 2023, at 2:58?PM, Mark Reinhold wrote: > > https://openjdk.org/jeps/463 > > Summary: Evolve the Java programming language so that students can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate dialect > of the language, students can write streamlined declarations for > single-class programs and then seamlessly expand their programs to use > more advanced features as their skills grow. This is a preview language > feature. > > - Mark From davidalayachew at gmail.com Wed Nov 1 21:23:51 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 1 Nov 2023 17:23:51 -0400 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: <20231101175845.9702264CBD7@eggemoggin.niobe.net> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: Hello Mark, Thank you for posting this! I really like the direction of simplifying concepts and reducing the surface size. Starting out with a smaller domain of concepts makes the universe easy to understand, not to mention, you can appreciate the expanded domain once you need to start introducing some programming-in-the-large concepts. > The new programmer encounters these concepts > at the worst possible time, before they learn > about variables and control flow, and when > they cannot appreciate the utility of > programming-in-the-large constructs for > keeping a large program well organized. > Instructors often offer the admonition, > "don't worry about that, you'll understand it > later." This is unsatisfying to them and > their students alike, and leaves students > with the enduring impression that the > language is complicated. Rereading this paragraph, I appreciate the wording of it very much. It helps us see the mindset of the student as clearly as possible. So much so that it raises 2 questions. 1. In the name of simplifying things for beginners, what is the reason why the main method is specifically called "main"? Would not "run" or something similar be better? The word "main" implies to me that it is the "main" method (out of all of the others). But that right there means I must be aware of the concept of there being multiple methods. But again, that's forcing the beginner to think about concepts that they don't yet need to. Most students' first programs will be solely contained in a single method. 2. Alternatively, could we have the name be irrelevant if it is the only method in the class? If we do that, then the concept of the "main" method would be really impactful, because, once you introduce the concept of multiple methods, students are likely to ask themselves "which method will get run first?" In that instance, the concept of a method called main wll be extremely intuitive and understandable. I really like this idea. I feel like we have an opportunity for a memorable "light bulb" moment in student's minds. If they ask themselves which method will be called now that there are multiple, the "main" method will make perfect sense the first time. It will complicate that launch protocol. For example, do we allow parameters? I say, it should follow suit with "main" semantics. Thank you for your time and help! David Alayachew On Wed, Nov 1, 2023 at 4:34?PM Mark Reinhold wrote: > https://openjdk.org/jeps/463 > > Summary: Evolve the Java programming language so that students can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate dialect > of the language, students can write streamlined declarations for > single-class programs and then seamlessly expand their programs to use > more advanced features as their skills grow. This is a preview language > feature. > > - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Nov 1 21:33:51 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 1 Nov 2023 17:33:51 -0400 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: And to be clear, irrelevant means, call it whatever you want. On Wed, Nov 1, 2023 at 5:23?PM David Alayachew wrote: > Hello Mark, > > Thank you for posting this! > > I really like the direction of simplifying concepts and reducing the > surface size. Starting out with a smaller domain of concepts makes the > universe easy to understand, not to mention, you can appreciate the > expanded domain once you need to start introducing some > programming-in-the-large concepts. > > > The new programmer encounters these concepts > > at the worst possible time, before they learn > > about variables and control flow, and when > > they cannot appreciate the utility of > > programming-in-the-large constructs for > > keeping a large program well organized. > > Instructors often offer the admonition, > > "don't worry about that, you'll understand it > > later." This is unsatisfying to them and > > their students alike, and leaves students > > with the enduring impression that the > > language is complicated. > > Rereading this paragraph, I appreciate the wording of it very much. It > helps us see the mindset of the student as clearly as possible. So much so > that it raises 2 questions. > > 1. In the name of simplifying things for beginners, what is the reason why > the main method is specifically called "main"? Would not "run" or something > similar be better? The word "main" implies to me that it is the "main" > method (out of all of the others). But that right there means I must be > aware of the concept of there being multiple methods. But again, that's > forcing the beginner to think about concepts that they don't yet need to. > Most students' first programs will be solely contained in a single method. > > 2. Alternatively, could we have the name be irrelevant if it is the only > method in the class? If we do that, then the concept of the "main" method > would be really impactful, because, once you introduce the concept of > multiple methods, students are likely to ask themselves "which method will > get run first?" In that instance, the concept of a method called main wll > be extremely intuitive and understandable. I really like this idea. I feel > like we have an opportunity for a memorable "light bulb" moment in > student's minds. If they ask themselves which method will be called now > that there are multiple, the "main" method will make perfect sense the > first time. It will complicate that launch protocol. For example, do we > allow parameters? I say, it should follow suit with "main" semantics. > > Thank you for your time and help! > David Alayachew > > On Wed, Nov 1, 2023 at 4:34?PM Mark Reinhold > wrote: > >> https://openjdk.org/jeps/463 >> >> Summary: Evolve the Java programming language so that students can >> write their first programs without needing to understand language >> features designed for large programs. Far from using a separate dialect >> of the language, students can write streamlined declarations for >> single-class programs and then seamlessly expand their programs to use >> more advanced features as their skills grow. This is a preview language >> feature. >> >> - Mark > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Nov 1 21:54:28 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 1 Nov 2023 17:54:28 -0400 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: <5401158c-1f6f-429c-cbd6-21f8bc53a677@oracle.com> > 1. In the name of simplifying things for beginners Any line of thinking that starts this way is dangerous, because it often leads to what ends up being a "beginner's dialect of Java", which means things to unlearn once the student graduates to "full programs".? Instead, what we want is for irrelevant details to fade into the background until they are needed.? Learning "a program begins with a main method" seems reasonable to put on the beginner's radar, in ways that the static-instance distinction does not.? The onramp should match speed and direction with the highway. > 2. Alternatively, could we have the name be irrelevant if it is the > only method in the class? If we did this, as soon as someone refactored their program to add a second method, we wouldn't know how to launch the program.? This is falling off the onramp before you get to the highway! -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Nov 1 22:07:54 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Wed, 1 Nov 2023 18:07:54 -0400 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: <5401158c-1f6f-429c-cbd6-21f8bc53a677@oracle.com> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> <5401158c-1f6f-429c-cbd6-21f8bc53a677@oracle.com> Message-ID: Hello, Thank you for the response! > > 1. In the name of simplifying things for beginners > > Any line of thinking that starts this way is dangerous, > because it often leads to what ends up being a > "beginner's dialect of Java", which means things to > unlearn once the student graduates to "full programs" Touch?. In this case, the unlearning (or rather, relearning) would be that the rest of the world uses main and that run is nothing more than an alias that is for beginners. Hence the dialect. That makes sense. > > 2. Alternatively, could we have the name be > > irrelevant if it is the only method in the class? > > If we did this, as soon as someone refactored their > program to add a second method, we wouldn't know > how to launch the program. This is falling off the > onramp before you get to the highway! Also fair. I had visualized it as whoever was teaching them that you can have more than one method would also teach them to disambiguate. But the way you described it is better. If we make the initial lift a little heavier by telling them that execution must start with a main method, then the student does not need to disambiguate. Furthermore, like you said, the act of adding another method does not affect/taint what is already there, whereas my suggestion does. Thank you for the help! David Alayachew On Wed, Nov 1, 2023 at 5:54?PM Brian Goetz wrote: > > 1. In the name of simplifying things for beginners > > > Any line of thinking that starts this way is dangerous, because it often > leads to what ends up being a "beginner's dialect of Java", which means > things to unlearn once the student graduates to "full programs". Instead, > what we want is for irrelevant details to fade into the background until > they are needed. Learning "a program begins with a main method" seems > reasonable to put on the beginner's radar, in ways that the static-instance > distinction does not. The onramp should match speed and direction with the > highway. > > 2. Alternatively, could we have the name be irrelevant if it is the only > method in the class? > > > If we did this, as soon as someone refactored their program to add a > second method, we wouldn't know how to launch the program. This is falling > off the onramp before you get to the highway! > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From numeralnathan at gmail.com Wed Nov 1 22:10:34 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Wed, 1 Nov 2023 15:10:34 -0700 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: <20231101175845.9702264CBD7@eggemoggin.niobe.net> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: As part of the JEP, can the static analysis tools emit a warning that a simple main() is in use? Perhaps, javac and the Eclipse compiler can output a warning when the project reaches a large enough size or the code shows that the programmer is ready to use the typical main(). If the .java file has public, static, and void, then it is time to use these on main(). PMD and/or SonarQube can always output a warning since these are not typically used for beginner student programs. On Wed, Nov 1, 2023 at 2:40?PM Mark Reinhold wrote: > https://openjdk.org/jeps/463 > > Summary: Evolve the Java programming language so that students can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate dialect > of the language, students can write streamlined declarations for > single-class programs and then seamlessly expand their programs to use > more advanced features as their skills grow. This is a preview language > feature. > > - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From numeralnathan at gmail.com Wed Nov 1 22:30:42 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Wed, 1 Nov 2023 15:30:42 -0700 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: <20231101175845.9702264CBD7@eggemoggin.niobe.net> References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: As part of the JEP, can the static analysis tools emit a warning that a simple main() is in use? Perhaps, javac and the Eclipse compiler can output a warning when the project reaches a large enough size or the code shows that the programmer is ready to use the typical main(). If the .java file has public, static, and void, then it is time to use these on main(). PMD and/or SonarQube can always output a warning since these are not typically used for beginner student programs. On Wed, Nov 1, 2023 at 2:40?PM Mark Reinhold wrote: > https://openjdk.org/jeps/463 > > Summary: Evolve the Java programming language so that students can > write their first programs without needing to understand language > features designed for large programs. Far from using a separate dialect > of the language, students can write streamlined declarations for > single-class programs and then seamlessly expand their programs to use > more advanced features as their skills grow. This is a preview language > feature. > > - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Nov 2 09:32:52 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 2 Nov 2023 09:32:52 +0000 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: Hi David On 01/11/2023 21:23, David Alayachew wrote: > 1. In the name of simplifying things for beginners, what is the reason > why the main method is specifically called "main"? Would not "run" or > something similar be better? The word "main" implies to me that it is > the "main" method (out of all of the others). But that right there > means I must be aware of the concept of there being multiple methods. > But again, that's forcing the beginner to think about concepts that > they don't yet need to. Most students' first programs will be solely > contained in a single method. I believe calling it any name other than "main" would compromise one of the main goals of this JEP, which is stated nicely in the "Growing a program" section (I actually believe this section is, IMHO, the most important one in the JEP, and the ones that is driving many of the decisions contained in it!): > Even so, all members are interpreted just as they are in an ordinary > class. To evolve an implicit class into an ordinary class, all we need > to do is wrap its declaration, excluding |import| statements, inside > an explicit |class| declaration. Perhaps there's a more intuitive name out there - but regular classes would still need a "magic" name to pick what they want to run. And since "main" is the magic name that's been used for the last 25 years, our hands were a bit forced here... > > 2. Alternatively, could we have the name be irrelevant if it is the > only method in the class? If we do that, then the concept of the > "main" method would be really impactful, because, once you introduce > the concept of multiple methods, students are likely to ask themselves > "which method will get run first?" In that instance, the concept of a > method called main wll be extremely intuitive and understandable. I > really like this idea. I feel like we have an opportunity for a > memorable "light bulb" moment in student's minds. If they ask > themselves which method will be called now that there are multiple, > the "main" method will make perfect sense the first time. It will > complicate that launch protocol. For example, do we allow parameters? > I say, it should follow suit with "main" semantics. Again, quoting from the above section: > Eliminating the |main| method altogether may seem like the natural > next step, but it would work against the goal of gracefully evolving a > first Java program to a larger one and would impose some non-obvious > restrictions (see below ). > Dropping the |void| modifier would similarly create a distinct Java > dialect. So, it seems natural for an implicit class with one method to behave exactly like an implicit class with two methods. Adding special rules for an implicit class with one method seems ad-hoc and likely to backfire. E.g. you add a method and your program no longer compiles or, if you are unlucky and you call the second method "main" now you launch that one instead, perhaps unkowingly. Cheers Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at sebfisch.de Thu Nov 2 11:13:50 2023 From: mail at sebfisch.de (Sebastian Fischer) Date: Thu, 2 Nov 2023 12:13:50 +0100 Subject: Allow case constants as nested patterns? Message-ID: Hello. I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. JEP 441 shows the following grammar for switch labels. SwitchLabel: case CaseConstant { , CaseConstant } case null [, default] case Pattern [ Guard ] default JEP 440 shows the following grammar for patterns. Pattern: TypePattern RecordPattern TypePattern: LocalVariableDeclaration RecordPattern: ReferenceType ( [ PatternList ] ) PatternList : Pattern { , Pattern } As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. sealed interface BoolExpr { enum Constant implements BoolExpr { TRUE, FALSE } record And(BoolExpr left, BoolExpr right) implements BoolExpr {} default BoolExpr recursively(UnaryOperator transform) { return transform.apply(switch (this) { case Constant c -> c; case And(var left, var right) -> new And( left.recursively(transform), right.recursively(transform) ); }); } default BoolExpr shortCircuit() { return recursively(expr -> switch (expr) { case And(var left, var unused) when left == Constant.FALSE -> Constant.FALSE; default -> expr; }); } } In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. Instead of using an enum, we can model constants as empty records as follows. sealed interface Constant extends BoolExpr permits True, False {} record True() implements Constant {} record False() implements Constant {} Now we can write `shortCircuit` using a nested record pattern. default BoolExpr shortCircuit() { return recursively(expr -> switch (expr) { case And(False(), var unused) -> new False(); default -> expr; }); } It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. default BoolExpr shortCircuit() { return recursively(expr -> switch (expr) { case And(Constant.FALSE, var unused) -> Constant.FALSE; default -> expr; }); } What are potential problems with allowing case constants as nested patterns? Kind regards, Sebastian -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Thu Nov 2 12:37:11 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Thu, 2 Nov 2023 08:37:11 -0400 Subject: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: Hello Maurizio, Thank you for your response! Yeah, I see now how my suggestions don't work out. Ultimately, my suggestions force us to think of things with a "beginner" version that doesn't align with the way things would go later. Like you mentioned with a program working with one method, but not 2. Or having one called run and another called main that just so happens to take a String[] parameter. Thank you for the insight! David Alayachew On Thu, Nov 2, 2023 at 5:33?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > Hi David > On 01/11/2023 21:23, David Alayachew wrote: > > 1. In the name of simplifying things for beginners, what is the reason why > the main method is specifically called "main"? Would not "run" or something > similar be better? The word "main" implies to me that it is the "main" > method (out of all of the others). But that right there means I must be > aware of the concept of there being multiple methods. But again, that's > forcing the beginner to think about concepts that they don't yet need to. > Most students' first programs will be solely contained in a single method. > > I believe calling it any name other than "main" would compromise one of > the main goals of this JEP, which is stated nicely in the "Growing a > program" section (I actually believe this section is, IMHO, the most > important one in the JEP, and the ones that is driving many of the > decisions contained in it!): > > Even so, all members are interpreted just as they are in an ordinary > class. To evolve an implicit class into an ordinary class, all we need to > do is wrap its declaration, excluding import statements, inside an > explicit class declaration. > > Perhaps there's a more intuitive name out there - but regular classes > would still need a "magic" name to pick what they want to run. And since > "main" is the magic name that's been used for the last 25 years, our hands > were a bit forced here... > > > > 2. Alternatively, could we have the name be irrelevant if it is the only > method in the class? If we do that, then the concept of the "main" method > would be really impactful, because, once you introduce the concept of > multiple methods, students are likely to ask themselves "which method will > get run first?" In that instance, the concept of a method called main wll > be extremely intuitive and understandable. I really like this idea. I feel > like we have an opportunity for a memorable "light bulb" moment in > student's minds. If they ask themselves which method will be called now > that there are multiple, the "main" method will make perfect sense the > first time. It will complicate that launch protocol. For example, do we > allow parameters? I say, it should follow suit with "main" semantics. > > Again, quoting from the above section: > > Eliminating the main method altogether may seem like the natural next > step, but it would work against the goal of gracefully evolving a first > Java program to a larger one and would impose some non-obvious restrictions > (see below ). Dropping the void > modifier would similarly create a distinct Java dialect. > > So, it seems natural for an implicit class with one method to behave > exactly like an implicit class with two methods. Adding special rules for > an implicit class with one method seems ad-hoc and likely to backfire. E.g. > you add a method and your program no longer compiles or, if you are unlucky > and you call the second method "main" now you launch that one instead, > perhaps unkowingly. > > Cheers > Maurizio > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Tue Nov 7 09:37:28 2023 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Tue, 7 Nov 2023 09:37:28 +0000 Subject: Allow case constants as nested patterns? In-Reply-To: References: Message-ID: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> Hi Sebastian, Yes, there has been some discussion about adding constant patterns if you look through the archive. There are interesting syntactic issues, but IIRC we have been waiting for the primitive type patterns feature to settle so we have a proper basis to deal with any type conversion questions. (For example, you write switch(new Box(b)) { case Box(0) -> ? } where b is a byte and 0 is an integer constant?) So, it?s on our radar :-) Gavin > On 2 Nov 2023, at 11:13, Sebastian Fischer wrote: > > Hello. > > I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. > > I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. > > JEP 441 shows the following grammar for switch labels. > > SwitchLabel: > case CaseConstant { , CaseConstant } > case null [, default] > case Pattern [ Guard ] > default > > JEP 440 shows the following grammar for patterns. > > Pattern: > TypePattern > RecordPattern > > TypePattern: > LocalVariableDeclaration > > RecordPattern: > ReferenceType ( [ PatternList ] ) > > PatternList : > Pattern { , Pattern } > > As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. > > sealed interface BoolExpr { > enum Constant implements BoolExpr { TRUE, FALSE } > record And(BoolExpr left, BoolExpr right) implements BoolExpr {} > > default BoolExpr recursively(UnaryOperator transform) { > return transform.apply(switch (this) { > case Constant c -> c; > case And(var left, var right) -> new And( > left.recursively(transform), > right.recursively(transform) > ); > }); > } > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(var left, var unused) > when left == Constant.FALSE -> Constant.FALSE; > default -> > expr; > }); > } > } > > In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. > > Instead of using an enum, we can model constants as empty records as follows. > > sealed interface Constant extends BoolExpr permits True, False {} > record True() implements Constant {} > record False() implements Constant {} > > Now we can write `shortCircuit` using a nested record pattern. > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(False(), var unused) -> new False(); > default -> expr; > }); > } > > It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(Constant.FALSE, var unused) -> Constant.FALSE; > default -> expr; > }); > } > > What are potential problems with allowing case constants as nested patterns? > > Kind regards, > Sebastian > > > > > From brian.goetz at oracle.com Tue Nov 7 14:30:30 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 7 Nov 2023 09:30:30 -0500 Subject: Allow case constants as nested patterns? In-Reply-To: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> References: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> Message-ID: To add to this: there are several categories of questions that we wanted to settle before considering constant patterns (which would (almost?) complete the rehabilitation of switch): ?- Syntactic.? If `0` is both a literal and a pattern, then locutions like `f(0)` can either be method invocations or pattern matches.? It was not obvious in the early days whether such ambiguities would pose roadblocks for using patterns in other contexts.? This is seeming more viable now but we didn't want to foreclose this path too early. ?- User perception.? Related to the above, if it is not obvious what `f(0)` means, even if the grammar can be parsed unambiguously, it might make code harder to read.? So we might hold out for a syntax that is somewhat wordier but more obvious. ?- Semantics.? At the beginning, it was very much not clear (to the point where our first ideas would have been pretty wrong) what the semantics of matching a constant are.? JEP 455 has been working through those issues, so we believe we now have a firm foundation for the meaning of `0` as a pattern. ?- Alignment with switch.? The "obvious" meaning of constant patterns may or may not align with the treatment of constants in switch today; this needs to be worked through carefully, otherwise refactoring a switch like: ??? case Foo(k) ??? case Foo(k') ??? case Foo(k'') to a switch like ??? case Foo(var x) { ??????? switch (x) { ??????????? case k ??????????? case k' ??????????? case k'' ???????? } ??? } will have subtle asymmetries. So to sum this up, constant patterns are an "obvious" addition, but which turn out to be very much non-obvious when you consider all the connections with other language features and future language directions.? So we've been waiting for these to settle. On 11/7/2023 4:37 AM, Gavin Bierman wrote: > Hi Sebastian, > > Yes, there has been some discussion about adding constant patterns if you look through the archive. There are interesting syntactic issues, but IIRC we have been waiting for the primitive type patterns feature to settle so we have a proper basis to deal with any type conversion questions. (For example, you write switch(new Box(b)) { case Box(0) -> ? } where b is a byte and 0 is an integer constant?) > > So, it?s on our radar :-) > > Gavin > >> On 2 Nov 2023, at 11:13, Sebastian Fischer wrote: >> >> Hello. >> >> I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. >> >> I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. >> >> JEP 441 shows the following grammar for switch labels. >> >> SwitchLabel: >> case CaseConstant { , CaseConstant } >> case null [, default] >> case Pattern [ Guard ] >> default >> >> JEP 440 shows the following grammar for patterns. >> >> Pattern: >> TypePattern >> RecordPattern >> >> TypePattern: >> LocalVariableDeclaration >> >> RecordPattern: >> ReferenceType ( [ PatternList ] ) >> >> PatternList : >> Pattern { , Pattern } >> >> As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. >> >> sealed interface BoolExpr { >> enum Constant implements BoolExpr { TRUE, FALSE } >> record And(BoolExpr left, BoolExpr right) implements BoolExpr {} >> >> default BoolExpr recursively(UnaryOperator transform) { >> return transform.apply(switch (this) { >> case Constant c -> c; >> case And(var left, var right) -> new And( >> left.recursively(transform), >> right.recursively(transform) >> ); >> }); >> } >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(var left, var unused) >> when left == Constant.FALSE -> Constant.FALSE; >> default -> >> expr; >> }); >> } >> } >> >> In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. >> >> Instead of using an enum, we can model constants as empty records as follows. >> >> sealed interface Constant extends BoolExpr permits True, False {} >> record True() implements Constant {} >> record False() implements Constant {} >> >> Now we can write `shortCircuit` using a nested record pattern. >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(False(), var unused) -> new False(); >> default -> expr; >> }); >> } >> >> It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(Constant.FALSE, var unused) -> Constant.FALSE; >> default -> expr; >> }); >> } >> >> What are potential problems with allowing case constants as nested patterns? >> >> Kind regards, >> Sebastian >> >> >> >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Tue Nov 7 15:10:32 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Tue, 7 Nov 2023 10:10:32 -0500 Subject: Reporting a minor pain point I had when working with Sealed Types recently Message-ID: Hello Amber Dev Team, I have been making extremely frequent use of sealed types and records to model Abstract Data Types, but the lack of local sealed types is becoming more and more of an annoyance to me. Annoyance is the correct word -- the cost I pay is in wasting time refactoring things. On rare occasions, I will refactor incorrectly and have to spend about 15-30 minutes reteaching myself what each one meant. This is certainly not an expensive cost. But this past week, I hit this problem multiple times back to back, such that the sum total was a few hours of refactoring across a full week of work. Because of that, this email felt warranted. To very quickly explain my situation, I have a bunch of projects I'm working on, each of which does a lot of work deserializing semi-structured outside data. So, an ideal use case for ADT's. I keep running into the same bar over and over again -- a project has many different types of data it needs to deserialize (>20 different data types), and several of those data types are quite similar to each other, such that the names end up being similar. When I go to refactor a class - either splitting it up or combining multiple classes into a single one, I usually end up either mixing up sealed types (using the incorrect one) or combining parent classes that both have private sealed types with the same name. This week was notable because almost all of my projects that I am working on ran into this same problem at around the same time. It's not a very big issue, but out of the 60+ hours I worked this week, I'd say about 3-4 of those hours were spent debugging and wasting time on fixing refactoring bugs. Admittedly, that's probably the worst-case scenario one can get for this problem, which shows that the scale of damage isn't very large. Also, I am pretty sure I know the reasons why it hasn't been done yet, and I don't contest them. However, I do want to share my experience in case that information influences any decision-making on the matter. Thank you for your time! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Nov 7 15:33:27 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 7 Nov 2023 10:33:27 -0500 Subject: Reporting a minor pain point I had when working with Sealed Types recently In-Reply-To: References: Message-ID: Local sealed classes live on that list of features that are reasonable to do, but always seem to have less leverage than other features we could work on. We've gone through a few rounds of removing unnecessarily nesting restrictions (e.g., local records, allowing statics in inner classes), but there is always more to do.? Local sealed classes is one of these.? (Local methods is another.) As you've observed, the workaround is obvious; move it to an outer level of nesting, or into a local class. On 11/7/2023 10:10 AM, David Alayachew wrote: > Hello Amber Dev Team, > > I have been making extremely frequent use of sealed types and records > to model Abstract Data Types, but the lack of local sealed types is > becoming more and more of an annoyance to me. > > Annoyance is the correct word -- the cost I pay is in wasting time > refactoring things. On rare occasions, I will refactor incorrectly and > have to spend about 15-30 minutes reteaching myself what each one > meant. This is certainly not an expensive cost. But this past week, I > hit this problem multiple times back to back, such that the sum total > was a few hours of refactoring across a full week of work. Because of > that, this email felt warranted. > > To very quickly explain my situation, I have a bunch of projects I'm > working on, each of which does a lot of work deserializing > semi-structured outside data. So, an ideal use case for ADT's. I keep > running into the same bar over and over again -- a project has many > different types of data it needs to deserialize (>20 different data > types), and several of those data types are quite similar to each > other, such that the names end up being similar. When I go to refactor > a class - either splitting it up or combining multiple classes into a > single one, I usually end up either mixing up sealed types (using the > incorrect one) or combining parent classes that both have private > sealed types with the same name. > > This week was notable because almost all of my projects that I am > working on ran into this same problem at around the same time. > > It's not a very big issue, but out of the 60+ hours I worked this > week, I'd say about 3-4 of those hours were spent debugging and > wasting time on fixing refactoring bugs. Admittedly, that's probably > the worst-case scenario one can get for this problem, which shows that > the scale of damage isn't very large. Also, I am pretty sure I know > the reasons why it hasn't been done yet, and I don't contest them. > However, I do want to share my experience in case that information > influences any decision-making on the matter. > > Thank you for your time! > David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Tue Nov 7 20:23:23 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 7 Nov 2023 20:23:23 +0000 Subject: [External] : Re: New candidate JEP: 463: Implicit Classes and Instance Main Methods (Second Preview) In-Reply-To: References: <20231101175845.9702264CBD7@eggemoggin.niobe.net> Message-ID: <8B8871F7-80FB-4318-A388-C6FC4862B3F4@oracle.com> > On 1 Nov 2023, at 22:10, Nathan Reynolds wrote: > > As part of the JEP, can the static analysis tools emit a warning that a simple main() is in use? Perhaps, javac and the Eclipse compiler can output a warning when the project reaches a large enough size or the code shows that the programmer is ready to use the typical main(). If the .java file has public, static, and void, then it is time to use these on main(). PMD and/or SonarQube can always output a warning since these are not typically used for beginner student programs. Why? These are features that beginners would likely enjoy using because they don?t require introducing concepts that aren?t needed at that time, but these are not feature that *only* beginners should use. In fact, a separate beginners? dialect is something that the JEP very much tries to avoid. Beginners may *need* this more, but it?s certainly not for their exclusive use. From davidalayachew at gmail.com Wed Nov 8 02:53:43 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Tue, 7 Nov 2023 21:53:43 -0500 Subject: Reporting a minor pain point I had when working with Sealed Types recently In-Reply-To: References: Message-ID: Definitely agreed, ty for the response. On Tue, Nov 7, 2023 at 10:33?AM Brian Goetz wrote: > Local sealed classes live on that list of features that are reasonable to > do, but always seem to have less leverage than other features we could work > on. We've gone through a few rounds of removing unnecessarily nesting > restrictions (e.g., local records, allowing statics in inner classes), but > there is always more to do. Local sealed classes is one of these. (Local > methods is another.) > > As you've observed, the workaround is obvious; move it to an outer level > of nesting, or into a local class. > > On 11/7/2023 10:10 AM, David Alayachew wrote: > > Hello Amber Dev Team, > > I have been making extremely frequent use of sealed types and records to > model Abstract Data Types, but the lack of local sealed types is becoming > more and more of an annoyance to me. > > Annoyance is the correct word -- the cost I pay is in wasting time > refactoring things. On rare occasions, I will refactor incorrectly and have > to spend about 15-30 minutes reteaching myself what each one meant. This is > certainly not an expensive cost. But this past week, I hit this problem > multiple times back to back, such that the sum total was a few hours of > refactoring across a full week of work. Because of that, this email felt > warranted. > > To very quickly explain my situation, I have a bunch of projects I'm > working on, each of which does a lot of work deserializing semi-structured > outside data. So, an ideal use case for ADT's. I keep running into the same > bar over and over again -- a project has many different types of data it > needs to deserialize (>20 different data types), and several of those data > types are quite similar to each other, such that the names end up being > similar. When I go to refactor a class - either splitting it up or > combining multiple classes into a single one, I usually end up either > mixing up sealed types (using the incorrect one) or combining parent > classes that both have private sealed types with the same name. > > This week was notable because almost all of my projects that I am working > on ran into this same problem at around the same time. > > It's not a very big issue, but out of the 60+ hours I worked this week, > I'd say about 3-4 of those hours were spent debugging and wasting time on > fixing refactoring bugs. Admittedly, that's probably the worst-case > scenario one can get for this problem, which shows that the scale of damage > isn't very large. Also, I am pretty sure I know the reasons why it hasn't > been done yet, and I don't contest them. However, I do want to share my > experience in case that information influences any decision-making on the > matter. > > Thank you for your time! > David Alayachew > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at sebfisch.de Wed Nov 8 12:35:50 2023 From: mail at sebfisch.de (Sebastian Fischer) Date: Wed, 8 Nov 2023 13:35:50 +0100 Subject: Allow case constants as nested patterns? In-Reply-To: References: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> Message-ID: Thank you both for your responses! I understand that more diverse kinds of nested patterns interact with multiple other planned extensions and in order to better understand those interactions, nested patterns have been restricted to record patterns for now. My question was less about constant patterns (or other unfinished extensions) and more about taking what is already possible at the top-level of a switch and allowing it also in nested pattern positions (probably caused by my hope that the notion of nested patterns could be extended incrementally with each new extension at the top-level). The example of refactoring a nested pattern into nested switches illustrates my intuition quite well: that nested patterns would have the same semantics as corresponding nested switches. The idea of unifying top-level with nested possibilities raises the question whether null patterns or even guards should be available in nested patterns. But I restricted my question to CaseConstant (in the currently supported form) because that is the most obvious gap and it complicates refactorings of empty records into enum constants. Personally, I think nested guards could be quite confusing but there might be a case for nested null patterns. Your summary helped me get an overview of previous considerations. I'll try to find more details in the archives and am looking forward to future discussions in the context of the mentioned JEPs. Sebastian On Tue, Nov 7, 2023 at 3:30?PM Brian Goetz wrote: > To add to this: there are several categories of questions that we wanted > to settle before considering constant patterns (which would (almost?) > complete the rehabilitation of switch): > > - Syntactic. If `0` is both a literal and a pattern, then locutions like > `f(0)` can either be method invocations or pattern matches. It was not > obvious in the early days whether such ambiguities would pose roadblocks > for using patterns in other contexts. This is seeming more viable now but > we didn't want to foreclose this path too early. > > - User perception. Related to the above, if it is not obvious what > `f(0)` means, even if the grammar can be parsed unambiguously, it might > make code harder to read. So we might hold out for a syntax that is > somewhat wordier but more obvious. > > - Semantics. At the beginning, it was very much not clear (to the point > where our first ideas would have been pretty wrong) what the semantics of > matching a constant are. JEP 455 has been working through those issues, so > we believe we now have a firm foundation for the meaning of `0` as a > pattern. > > - Alignment with switch. The "obvious" meaning of constant patterns may > or may not align with the treatment of constants in switch today; this > needs to be worked through carefully, otherwise refactoring a switch like: > > case Foo(k) > case Foo(k') > case Foo(k'') > > to a switch like > > case Foo(var x) { > switch (x) { > case k > case k' > case k'' > } > } > > will have subtle asymmetries. > > So to sum this up, constant patterns are an "obvious" addition, but which > turn out to be very much non-obvious when you consider all the connections > with other language features and future language directions. So we've been > waiting for these to settle. > > On 11/7/2023 4:37 AM, Gavin Bierman wrote: > > Hi Sebastian, > > Yes, there has been some discussion about adding constant patterns if you look through the archive. There are interesting syntactic issues, but IIRC we have been waiting for the primitive type patterns feature to settle so we have a proper basis to deal with any type conversion questions. (For example, you write switch(new Box(b)) { case Box(0) -> ? } where b is a byte and 0 is an integer constant?) > > So, it?s on our radar :-) > > Gavin > > > On 2 Nov 2023, at 11:13, Sebastian Fischer wrote: > > Hello. > > I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. > > I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. > > JEP 441 shows the following grammar for switch labels. > > SwitchLabel: > case CaseConstant { , CaseConstant } > case null [, default] > case Pattern [ Guard ] > default > > JEP 440 shows the following grammar for patterns. > > Pattern: > TypePattern > RecordPattern > > TypePattern: > LocalVariableDeclaration > > RecordPattern: > ReferenceType ( [ PatternList ] ) > > PatternList : > Pattern { , Pattern } > > As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. > > sealed interface BoolExpr { > enum Constant implements BoolExpr { TRUE, FALSE } > record And(BoolExpr left, BoolExpr right) implements BoolExpr {} > > default BoolExpr recursively(UnaryOperator transform) { > return transform.apply(switch (this) { > case Constant c -> c; > case And(var left, var right) -> new And( > left.recursively(transform), > right.recursively(transform) > ); > }); > } > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(var left, var unused) > when left == Constant.FALSE -> Constant.FALSE; > default -> > expr; > }); > } > } > > In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. > > Instead of using an enum, we can model constants as empty records as follows. > > sealed interface Constant extends BoolExpr permits True, False {} > record True() implements Constant {} > record False() implements Constant {} > > Now we can write `shortCircuit` using a nested record pattern. > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(False(), var unused) -> new False(); > default -> expr; > }); > } > > It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. > > default BoolExpr shortCircuit() { > return recursively(expr -> switch (expr) { > case And(Constant.FALSE, var unused) -> Constant.FALSE; > default -> expr; > }); > } > > What are potential problems with allowing case constants as nested patterns? > > Kind regards, > Sebastian > > > > > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Nov 8 14:26:19 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 8 Nov 2023 09:26:19 -0500 Subject: Allow case constants as nested patterns? In-Reply-To: References: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> Message-ID: <4501dad1-d4ec-e2c0-e56c-8ceb27c7ae33@oracle.com> I think you are probably thinking that "taking what is already possible at the top level and allowing it in nested position" is somehow considerably simpler than "constant patterns", and therefore a suitable stopgap, but that's not the case.? (Not only is it essentially the same problem, but a stopgap always leaves the possibility we will foreclose on getting to the real thing.) It is an unfortunate artifact of transition (ideally, temporary) that a switch can mix "constant cases" and "pattern cases"; this division adds spec complexity and user friction for no direct benefit. As to null, since `null` is a literal just like `0`, we would hope that this would fit cleanly into constant patterns as well. On 11/8/2023 7:35 AM, Sebastian Fischer wrote: > Thank you both for your responses! > > I understand that more diverse kinds of nested patterns interact with > multiple other planned extensions and in order to better understand > those interactions, nested patterns have been restricted to record > patterns for now. > > My question was less about constant patterns (or other unfinished > extensions) and more about taking what is already possible at the > top-level of a switch and allowing it also in nested pattern positions > (probably caused by my hope that the notion of nested patterns could > be extended incrementally with each new extension at the top-level). > The example of refactoring a nested pattern into nested switches > illustrates my intuition quite well: that nested patterns would have > the same semantics as corresponding nested switches. > > The idea of unifying top-level with nested possibilities raises the > question whether null patterns or even guards should be available in > nested patterns. But I restricted my question to CaseConstant (in the > currently supported form) because that is the most obvious gap and it > complicates refactorings of empty records into enum constants. > Personally, I think nested guards could be quite confusing but there > might be a case for nested null patterns. > > Your summary helped me get an overview of previous considerations. > I'll try to find more details in the archives and am looking forward > to future discussions in the context of the mentioned JEPs. > > Sebastian > > On Tue, Nov 7, 2023 at 3:30?PM Brian Goetz wrote: > > To add to this: there are several categories of questions that we > wanted to settle before considering constant patterns (which would > (almost?) complete the rehabilitation of switch): > > ?- Syntactic.? If `0` is both a literal and a pattern, then > locutions like `f(0)` can either be method invocations or pattern > matches.? It was not obvious in the early days whether such > ambiguities would pose roadblocks for using patterns in other > contexts.? This is seeming more viable now but we didn't want to > foreclose this path too early. > > ?- User perception.? Related to the above, if it is not obvious > what `f(0)` means, even if the grammar can be parsed > unambiguously, it might make code harder to read.? So we might > hold out for a syntax that is somewhat wordier but more obvious. > > ?- Semantics.? At the beginning, it was very much not clear (to > the point where our first ideas would have been pretty wrong) what > the semantics of matching a constant are.? JEP 455 has been > working through those issues, so we believe we now have a firm > foundation for the meaning of `0` as a pattern. > > ?- Alignment with switch.? The "obvious" meaning of constant > patterns may or may not align with the treatment of constants in > switch today; this needs to be worked through carefully, otherwise > refactoring a switch like: > > ??? case Foo(k) > ??? case Foo(k') > ??? case Foo(k'') > > to a switch like > > ??? case Foo(var x) { > ??????? switch (x) { > ??????????? case k > ??????????? case k' > ??????????? case k'' > ???????? } > ??? } > > will have subtle asymmetries. > > So to sum this up, constant patterns are an "obvious" addition, > but which turn out to be very much non-obvious when you consider > all the connections with other language features and future > language directions.? So we've been waiting for these to settle. > > On 11/7/2023 4:37 AM, Gavin Bierman wrote: >> Hi Sebastian, >> >> Yes, there has been some discussion about adding constant patterns if you look through the archive. There are interesting syntactic issues, but IIRC we have been waiting for the primitive type patterns feature to settle so we have a proper basis to deal with any type conversion questions. (For example, you write switch(new Box(b)) { case Box(0) -> ? } where b is a byte and 0 is an integer constant?) >> >> So, it?s on our radar :-) >> >> Gavin >> >>> On 2 Nov 2023, at 11:13, Sebastian Fischer wrote: >>> >>> Hello. >>> >>> I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. >>> >>> I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. >>> >>> JEP 441 shows the following grammar for switch labels. >>> >>> SwitchLabel: >>> case CaseConstant { , CaseConstant } >>> case null [, default] >>> case Pattern [ Guard ] >>> default >>> >>> JEP 440 shows the following grammar for patterns. >>> >>> Pattern: >>> TypePattern >>> RecordPattern >>> >>> TypePattern: >>> LocalVariableDeclaration >>> >>> RecordPattern: >>> ReferenceType ( [ PatternList ] ) >>> >>> PatternList : >>> Pattern { , Pattern } >>> >>> As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. >>> >>> sealed interface BoolExpr { >>> enum Constant implements BoolExpr { TRUE, FALSE } >>> record And(BoolExpr left, BoolExpr right) implements BoolExpr {} >>> >>> default BoolExpr recursively(UnaryOperator transform) { >>> return transform.apply(switch (this) { >>> case Constant c -> c; >>> case And(var left, var right) -> new And( >>> left.recursively(transform), >>> right.recursively(transform) >>> ); >>> }); >>> } >>> >>> default BoolExpr shortCircuit() { >>> return recursively(expr -> switch (expr) { >>> case And(var left, var unused) >>> when left == Constant.FALSE -> Constant.FALSE; >>> default -> >>> expr; >>> }); >>> } >>> } >>> >>> In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. >>> >>> Instead of using an enum, we can model constants as empty records as follows. >>> >>> sealed interface Constant extends BoolExpr permits True, False {} >>> record True() implements Constant {} >>> record False() implements Constant {} >>> >>> Now we can write `shortCircuit` using a nested record pattern. >>> >>> default BoolExpr shortCircuit() { >>> return recursively(expr -> switch (expr) { >>> case And(False(), var unused) -> new False(); >>> default -> expr; >>> }); >>> } >>> >>> It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. >>> >>> default BoolExpr shortCircuit() { >>> return recursively(expr -> switch (expr) { >>> case And(Constant.FALSE, var unused) -> Constant.FALSE; >>> default -> expr; >>> }); >>> } >>> >>> What are potential problems with allowing case constants as nested patterns? >>> >>> Kind regards, >>> Sebastian >>> >>> >>> >>> >>> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From mail at sebfisch.de Wed Nov 8 15:00:26 2023 From: mail at sebfisch.de (Sebastian Fischer) Date: Wed, 8 Nov 2023 16:00:26 +0100 Subject: Allow case constants as nested patterns? In-Reply-To: <4501dad1-d4ec-e2c0-e56c-8ceb27c7ae33@oracle.com> References: <5B78C396-7A18-42E5-944D-D841C1E68EE0@oracle.com> <4501dad1-d4ec-e2c0-e56c-8ceb27c7ae33@oracle.com> Message-ID: You are on the right track about my thinking. However, I would not say "considerably simpler" but would consider the semantics to be clear via your proposed refactoring. (In other languages, the meaning of nested patterns is explained via translation into nested matchings.) I fully agree with your second paragraph. It was this division between constant and pattern cases that seemed odd to me when I saw the grammar. I briefly thought about an alternative, but it seemed non-trivial to fully get rid of some form of distinction, because having multiple patterns in a single case only seems reasonable if the patterns do not introduce variables. On Wed, Nov 8, 2023, 15:26 Brian Goetz wrote: > I think you are probably thinking that "taking what is already possible at > the top level and allowing it in nested position" is somehow considerably > simpler than "constant patterns", and therefore a suitable stopgap, but > that's not the case. (Not only is it essentially the same problem, but a > stopgap always leaves the possibility we will foreclose on getting to the > real thing.) > > It is an unfortunate artifact of transition (ideally, temporary) that a > switch can mix "constant cases" and "pattern cases"; this division adds > spec complexity and user friction for no direct benefit. > > As to null, since `null` is a literal just like `0`, we would hope that > this would fit cleanly into constant patterns as well. > > On 11/8/2023 7:35 AM, Sebastian Fischer wrote: > > Thank you both for your responses! > > I understand that more diverse kinds of nested patterns interact with > multiple other planned extensions and in order to better understand those > interactions, nested patterns have been restricted to record patterns for > now. > > My question was less about constant patterns (or other unfinished > extensions) and more about taking what is already possible at the top-level > of a switch and allowing it also in nested pattern positions (probably > caused by my hope that the notion of nested patterns could be extended > incrementally with each new extension at the top-level). The example of > refactoring a nested pattern into nested switches illustrates my intuition > quite well: that nested patterns would have the same semantics as > corresponding nested switches. > > The idea of unifying top-level with nested possibilities raises the > question whether null patterns or even guards should be available in nested > patterns. But I restricted my question to CaseConstant (in the currently > supported form) because that is the most obvious gap and it complicates > refactorings of empty records into enum constants. Personally, I think > nested guards could be quite confusing but there might be a case for nested > null patterns. > > Your summary helped me get an overview of previous considerations. I'll > try to find more details in the archives and am looking forward to future > discussions in the context of the mentioned JEPs. > > Sebastian > > On Tue, Nov 7, 2023 at 3:30?PM Brian Goetz wrote: > >> To add to this: there are several categories of questions that we wanted >> to settle before considering constant patterns (which would (almost?) >> complete the rehabilitation of switch): >> >> - Syntactic. If `0` is both a literal and a pattern, then locutions >> like `f(0)` can either be method invocations or pattern matches. It was >> not obvious in the early days whether such ambiguities would pose >> roadblocks for using patterns in other contexts. This is seeming more >> viable now but we didn't want to foreclose this path too early. >> >> - User perception. Related to the above, if it is not obvious what >> `f(0)` means, even if the grammar can be parsed unambiguously, it might >> make code harder to read. So we might hold out for a syntax that is >> somewhat wordier but more obvious. >> >> - Semantics. At the beginning, it was very much not clear (to the point >> where our first ideas would have been pretty wrong) what the semantics of >> matching a constant are. JEP 455 has been working through those issues, so >> we believe we now have a firm foundation for the meaning of `0` as a >> pattern. >> >> - Alignment with switch. The "obvious" meaning of constant patterns may >> or may not align with the treatment of constants in switch today; this >> needs to be worked through carefully, otherwise refactoring a switch like: >> >> case Foo(k) >> case Foo(k') >> case Foo(k'') >> >> to a switch like >> >> case Foo(var x) { >> switch (x) { >> case k >> case k' >> case k'' >> } >> } >> >> will have subtle asymmetries. >> >> So to sum this up, constant patterns are an "obvious" addition, but which >> turn out to be very much non-obvious when you consider all the connections >> with other language features and future language directions. So we've been >> waiting for these to settle. >> >> On 11/7/2023 4:37 AM, Gavin Bierman wrote: >> >> Hi Sebastian, >> >> Yes, there has been some discussion about adding constant patterns if you look through the archive. There are interesting syntactic issues, but IIRC we have been waiting for the primitive type patterns feature to settle so we have a proper basis to deal with any type conversion questions. (For example, you write switch(new Box(b)) { case Box(0) -> ? } where b is a byte and 0 is an integer constant?) >> >> So, it?s on our radar :-) >> >> Gavin >> >> >> On 2 Nov 2023, at 11:13, Sebastian Fischer wrote: >> >> Hello. >> >> I would like to improve my understanding of the interaction of two JEPs: Pattern matching for switch and Record patterns. >> >> I am new to this list so might have missed previous discussion about this but could not find what I was looking for in the archives. >> >> JEP 441 shows the following grammar for switch labels. >> >> SwitchLabel: >> case CaseConstant { , CaseConstant } >> case null [, default] >> case Pattern [ Guard ] >> default >> >> JEP 440 shows the following grammar for patterns. >> >> Pattern: >> TypePattern >> RecordPattern >> >> TypePattern: >> LocalVariableDeclaration >> >> RecordPattern: >> ReferenceType ( [ PatternList ] ) >> >> PatternList : >> Pattern { , Pattern } >> >> As a consequence it is not possible to have case constants in the pattern list of a record pattern. For example consider the following definitions modeling (a simplified version of) boolean expressions. >> >> sealed interface BoolExpr { >> enum Constant implements BoolExpr { TRUE, FALSE } >> record And(BoolExpr left, BoolExpr right) implements BoolExpr {} >> >> default BoolExpr recursively(UnaryOperator transform) { >> return transform.apply(switch (this) { >> case Constant c -> c; >> case And(var left, var right) -> new And( >> left.recursively(transform), >> right.recursively(transform) >> ); >> }); >> } >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(var left, var unused) >> when left == Constant.FALSE -> Constant.FALSE; >> default -> >> expr; >> }); >> } >> } >> >> In the definition of `shortCircuit` (which does partial evaluation) we need to use a guard to check if the left argument of `And` is false. >> >> Instead of using an enum, we can model constants as empty records as follows. >> >> sealed interface Constant extends BoolExpr permits True, False {} >> record True() implements Constant {} >> record False() implements Constant {} >> >> Now we can write `shortCircuit` using a nested record pattern. >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(False(), var unused) -> new False(); >> default -> expr; >> }); >> } >> >> It would be convenient to be able to use a nested pattern instead of a guard with the original definition using an enum for constants. Here is a hypothetical implementation of `shortCircuit` that is currently not supported. >> >> default BoolExpr shortCircuit() { >> return recursively(expr -> switch (expr) { >> case And(Constant.FALSE, var unused) -> Constant.FALSE; >> default -> expr; >> }); >> } >> >> What are potential problems with allowing case constants as nested patterns? >> >> Kind regards, >> Sebastian >> >> >> >> >> >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ella.ananeva at oracle.com Wed Nov 8 18:18:19 2023 From: ella.ananeva at oracle.com (Ella Ananeva) Date: Wed, 8 Nov 2023 18:18:19 +0000 Subject: instanceof with primitive type Message-ID: Hi team, Reading JEP 455 spec, I see this: The type of the expression RelationalExpression can be a reference type, a primitive type or the null type. And then, later: The following rules apply when instanceof is the pattern match operator: * The type of the expression RelationalExpression must be a reference type or the null type, or a compile-time error occurs. But I would expect that primitive types in patterns should be good, too. And in the freshest version of JEP_455 JDK, both examples compile and print ?Yes?: Integer x = 5; if (x instanceof int y) System.out.println("Yes"); int x = 5; if (x instanceof Integer y) System.out.println("Yes"); Shouldn?t the spec be updated? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From angelos.bimpoudis at oracle.com Wed Nov 8 22:56:41 2023 From: angelos.bimpoudis at oracle.com (Angelos Bimpoudis) Date: Wed, 8 Nov 2023 22:56:41 +0000 Subject: instanceof with primitive type In-Reply-To: References: Message-ID: Hello Ella, Indeed. The bullet you showed is now deleted from both. The line you have put in bold, replaces the other two. Thanks for bringing this up. Aggelos ________________________________ From: amber-dev on behalf of Ella Ananeva Sent: 08 November 2023 19:18 To: amber-dev at openjdk.org Subject: instanceof with primitive type Hi team, Reading JEP 455 spec, I see this: The type of the expression RelationalExpression can be a reference type, a primitive type or the null type. And then, later: The following rules apply when instanceof is the pattern match operator: * The type of the expression RelationalExpression must be a reference type or the null type, or a compile-time error occurs. But I would expect that primitive types in patterns should be good, too. And in the freshest version of JEP_455 JDK, both examples compile and print ?Yes?: Integer x = 5; if (x instanceof int y) System.out.println("Yes"); int x = 5; if (x instanceof Integer y) System.out.println("Yes"); Shouldn?t the spec be updated? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From ella.ananeva at oracle.com Wed Nov 8 23:08:04 2023 From: ella.ananeva at oracle.com (Ella Ananeva) Date: Wed, 8 Nov 2023 23:08:04 +0000 Subject: instanceof with primitive type In-Reply-To: References: Message-ID: Thank you very much for addressing this issue, Angelos! I have another question. What is our approach to treating scenarios when we use instanceof of null type with cast? Byte b = null; If (!(b instanceof byte)) System.our.println(?Yes?); //prints ?Yes? In the spec, A reference conversion may not complete normally, namely: * An unboxing conversion may raise a NullPointerException Here, no exception is thrown., so the behavior is as if we had a null type instanceof with a reference type in the pattern. But we have a primitive type in the pattern, so I would assume there should be some conversion going on? Precisely the scenario described in the assertion? BTW if I do a similar thing in switch, there will be an exception: Byte y = null; try { switch (y) { case byte x: System.out.println("converted"); default: System.out.println("not converted"); } } catch (NullPointerException ex) { System.out.println("Threw exception"); } This code prints ?Threw exception.? Shouldn?t the behavior of switch and instanceof be similar in this situation? Thank you, Ella From: Angelos Bimpoudis Date: Wednesday, November 8, 2023 at 2:56 PM To: Ella Ananeva , amber-dev at openjdk.org Subject: Re: instanceof with primitive type Hello Ella, Indeed. The bullet you showed is now deleted from both. The line you have put in bold, replaces the other two. Thanks for bringing this up. Aggelos ________________________________ From: amber-dev on behalf of Ella Ananeva Sent: 08 November 2023 19:18 To: amber-dev at openjdk.org Subject: instanceof with primitive type Hi team, Reading JEP 455 spec, I see this: The type of the expression RelationalExpression can be a reference type, a primitive type or the null type. And then, later: The following rules apply when instanceof is the pattern match operator: * The type of the expression RelationalExpression must be a reference type or the null type, or a compile-time error occurs. But I would expect that primitive types in patterns should be good, too. And in the freshest version of JEP_455 JDK, both examples compile and print ?Yes?: Integer x = 5; if (x instanceof int y) System.out.println("Yes"); int x = 5; if (x instanceof Integer y) System.out.println("Yes"); Shouldn?t the spec be updated? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Nov 9 01:38:01 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 8 Nov 2023 20:38:01 -0500 Subject: instanceof with primitive type In-Reply-To: References: Message-ID: <1dd2b28d-d7b0-8072-5377-4b8fab6c4b59@oracle.com> Unfortunately the behavior of instanceof and switch has always been different on this matter; instanceof evaluates to false when presented with a null, and switch throws NPE when presented with a null.? (They both dislike nulls, but one is more tolerant than the other.) When we added pattern support to switch, we extended this behavior to support `null` case labels.? If a switch has a `case null`, then when given a null selector, the appropriate case will be run, rather than the switch completing abruptly with NPE.? This preserves compatibility with existing code, while enabling null to be treated as "just another value" if desired. So the NPE you are seeing is not coming from the unboxing operation in `case byte x`, but before we even enter the switch, because the first thing switch does is evaluate the selector, and if that succeeds, checks for null, and if null, and no `case null` present, the switch completes abruptly with NPE. On 11/8/2023 6:08 PM, Ella Ananeva wrote: > > Thank you very much for addressing this issue, Angelos! > > I have another question. What is our approach to treating scenarios > when we use instanceof of null type with cast? > > Byte b = null; > > If (!(b instanceof byte)) ?System.our.println(?Yes?); //prints ?Yes? > > In the spec, > > A reference conversion may not complete normally, namely: > > * An unboxing conversion may raise a NullPointerException > > Here, no exception is thrown., so the behavior is as if we had a null > type instanceof with a reference type in the pattern. But we have a > primitive type in the pattern, so I would assume there should be some > conversion going on? Precisely the scenario described in the > assertion? BTW if I do a similar thing in switch, there will be an > exception: > > Byte y = null; > try { > switch (y) { > case byte x: System./out/.println("converted"); > default: System./out/.println("not converted"); > ??? } > } catch (NullPointerException ex) { > System./out/.println("Threw exception"); > } > > This code prints ?Threw exception.? > > Shouldn?t the behavior of switch and instanceof be similar in this > situation? > > Thank you, > > Ella > > *From: *Angelos Bimpoudis > *Date: *Wednesday, November 8, 2023 at 2:56 PM > *To: *Ella Ananeva , amber-dev at openjdk.org > > *Subject: *Re: instanceof with primitive type > > Hello Ella, > > Indeed. The bullet you showed is now deleted from both. The line you > have put in bold, replaces the other two. > > Thanks for bringing this up. > > Aggelos > > ------------------------------------------------------------------------ > > *From:*amber-dev on behalf of Ella > Ananeva > *Sent:* 08 November 2023 19:18 > *To:* amber-dev at openjdk.org > *Subject:* instanceof with primitive type > > Hi team, > > Reading JEP 455 spec > , > I see this: > > *The type of the expression */*RelationalExpression*/*can be a > reference type, a primitive type* *or the null type.* > > And then, later: > > The following rules apply when |instanceof| is the pattern match operator: > > * The type of the expression /RelationalExpression/ must be a > reference type or the null type, or a compile-time error occurs. > > But I would expect that primitive types in patterns should be good, > too. And in the freshest version of JEP_455 JDK > , > both examples compile and print ?Yes?: > > Integer x = 5; > if (x instanceof int y) System./out/.println("Yes"); > > int x = 5; > if (x instanceof Integer y) System./out/.println("Yes"); > > Shouldn?t the spec be updated? > > Thank you, > > Ella Ananeva > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ella.ananeva at oracle.com Thu Nov 9 18:52:38 2023 From: ella.ananeva at oracle.com (Ella Ananeva) Date: Thu, 9 Nov 2023 18:52:38 +0000 Subject: instanceof with primitive type In-Reply-To: <1dd2b28d-d7b0-8072-5377-4b8fab6c4b59@oracle.com> References: <1dd2b28d-d7b0-8072-5377-4b8fab6c4b59@oracle.com> Message-ID: Thank you so much for clarification, Brian. From: Brian Goetz Date: Wednesday, November 8, 2023 at 5:38 PM To: Ella Ananeva , Angelos Bimpoudis , amber-dev at openjdk.org Subject: Re: instanceof with primitive type Unfortunately the behavior of instanceof and switch has always been different on this matter; instanceof evaluates to false when presented with a null, and switch throws NPE when presented with a null. (They both dislike nulls, but one is more tolerant than the other.) When we added pattern support to switch, we extended this behavior to support `null` case labels. If a switch has a `case null`, then when given a null selector, the appropriate case will be run, rather than the switch completing abruptly with NPE. This preserves compatibility with existing code, while enabling null to be treated as "just another value" if desired. So the NPE you are seeing is not coming from the unboxing operation in `case byte x`, but before we even enter the switch, because the first thing switch does is evaluate the selector, and if that succeeds, checks for null, and if null, and no `case null` present, the switch completes abruptly with NPE. On 11/8/2023 6:08 PM, Ella Ananeva wrote: Thank you very much for addressing this issue, Angelos! I have another question. What is our approach to treating scenarios when we use instanceof of null type with cast? Byte b = null; If (!(b instanceof byte)) System.our.println(?Yes?); //prints ?Yes? In the spec, A reference conversion may not complete normally, namely: 1. An unboxing conversion may raise a NullPointerException Here, no exception is thrown., so the behavior is as if we had a null type instanceof with a reference type in the pattern. But we have a primitive type in the pattern, so I would assume there should be some conversion going on? Precisely the scenario described in the assertion? BTW if I do a similar thing in switch, there will be an exception: Byte y = null; try { switch (y) { case byte x: System.out.println("converted"); default: System.out.println("not converted"); } } catch (NullPointerException ex) { System.out.println("Threw exception"); } This code prints ?Threw exception.? Shouldn?t the behavior of switch and instanceof be similar in this situation? Thank you, Ella From: Angelos Bimpoudis Date: Wednesday, November 8, 2023 at 2:56 PM To: Ella Ananeva , amber-dev at openjdk.org Subject: Re: instanceof with primitive type Hello Ella, Indeed. The bullet you showed is now deleted from both. The line you have put in bold, replaces the other two. Thanks for bringing this up. Aggelos ________________________________ From: amber-dev on behalf of Ella Ananeva Sent: 08 November 2023 19:18 To: amber-dev at openjdk.org Subject: instanceof with primitive type Hi team, Reading JEP 455 spec, I see this: The type of the expression RelationalExpression can be a reference type, a primitive type or the null type. And then, later: The following rules apply when instanceof is the pattern match operator: 1. The type of the expression RelationalExpression must be a reference type or the null type, or a compile-time error occurs. But I would expect that primitive types in patterns should be good, too. And in the freshest version of JEP_455 JDK, both examples compile and print ?Yes?: Integer x = 5; if (x instanceof int y) System.out.println("Yes"); int x = 5; if (x instanceof Integer y) System.out.println("Yes"); Shouldn?t the spec be updated? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Fri Nov 10 16:40:11 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Fri, 10 Nov 2023 11:40:11 -0500 Subject: Want some official clarification on a quirk about pattern-matching for instanceof Message-ID: Hello Amber Dev Team, Someone on StackOverflow raised an excellent question about Pattern-Matching for instanceof, and I would like to get a response from one of you to include in the answer. Here is the link. https://stackoverflow.com/questions/77453336/instanceof-pattern-matching-in-java-not-compiling#77453336 To summarize, the book that they were reading (Java: The Complete Reference, 12th Edition by Herbert Schildt) had the following quote. -----QUOTE_START---- (with minor modifications for readability) ```java Number myOb = Integer.valueOf(9); int count = 10; // vv---- Conditional AND Operator if ( (count < 100) && myOb instanceof Integer iObj) { iObj = count; } ``` The above fragment compiles because the if block will execute only when both sides of the && are true. Thus, the use of iObj in the if block is valid. However, a compilation error will result if you tried to use the & rather than the &&, as shown below. ```java Number myOb = Integer.valueOf(9); int count = 10; // v----- Bitwise Logical AND Operator if ( (count < 100) & myOb instanceof Integer iObj) { iObj = count; } ``` In this case, the compiler cannot know whether or not iObj will be in scope in the if block because the right side of the & will not necessarily be evaluated. ----QUOTE_END---- When compiling the second example, it is exactly as the author says, we get told that the variable may not necessarily be in scope. Here is the error I get using OpenJDK 22 Early Access. ```java $ java --version openjdk 22-ea 2024-03-19 OpenJDK Runtime Environment (build 22-ea+20-1570) OpenJDK 64-Bit Server VM (build 22-ea+20-1570, mixed mode, sharing) $ javac --version javac 22-ea $ cat abc.java public class abc { public static void main(String[] args) { Number myOb = Integer.valueOf(9); int count = 10; if ( (count < 100) & myOb instanceof Integer iObj ) { iObj = count; } } } $ javac abc.java abc.java:15: error: cannot find symbol iObj = count; ^ symbol: variable iObj location: class abc 1 error ``` I feel like I have a very good idea of why this might be the case, but I lack the terminology to put it into words correctly. Could someone help me out? Thank you for your time and help! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From tzengshinfu at gmail.com Sat Nov 11 10:09:43 2023 From: tzengshinfu at gmail.com (tzengshinfu) Date: Sat, 11 Nov 2023 18:09:43 +0800 Subject: Is there a possibility of the string equality operator (==) being fixed? In-Reply-To: References: Message-ID: Hello, folks! Have a great weekend! I've been busy migrating our system from C# to the Java ecosystem (we also switched our system's host OS from Windows Server to Linux), so my responses are a bit delayed. Thanks to Jens & Pedro for sharing. I noticed that in C#, there is an attempt to make the comparison behavior of String class/Nullable class values similar to built-in value types. PS: For address comparison, the static method object::ReferenceEquals is used. Let me modify the previous C# example: ```csharp string s1 = new string(new char[] { '1' }); string s2 = new string(new char[] { '1' }); object o1 = s1; object o2 = s1; Console.WriteLine(s1 == s2); // True, same value Console.WriteLine(object.ReferenceEquals(o1, o2)); // True, same reference ``` This is equivalent to the following Java example: ```java String s1 = new String("1"); String s2 = new String("1"); Object o1 = s1; Object o2 = s1; System.out.println(s1.equals(s2)); // true, same value System.out.println(o1 == o2); // true, same reference ``` Now that I know more, understand the history, and gradually grasp the design philosophy of Java (Thank you, Brian), I realize there are two worlds. Initially entering Java, I wasn't aware of these two worlds; I just wondered why I could use == for value comparison in the world of primitive data types, but for string comparison, I had to use String::equals. At that time, I just wished that the commonly used String class could be compared by value like primitive data types. C#, as a later entrant with a smaller ecosystem impact, could make adjustments to bridge the gap between these two worlds. However, Java, being the pioneer, would face too high a cost to make such changes. I now understand that Java tends to be detailed, revealing as many details as possible. Object value comparison is not simple; a class can have multiple fields, and fields can be other classes. When comparing two classes' values, you can compare all fields or just a few. Additionally, Java does not support operator overloading. Overriding Object::equals to perform value comparison is reasonable. I still look forward to the arrival of the era of value types mentioned by Brian, where we can use a single method for value comparison in most cases. Thank you for your insights, John. Currently, in the Web API parameters, I use Integer to represent nullable (similar to C#'s int?), and it works well. Lastly, let me mention a feature of C#: syntactic sugar. Honestly, after coming to the Java world, I've given up on sugar (except for var declarations). After several developments in C#, I find it challenging to understand the current version. Syntactic sugar, such as extension methods and operator overloading, can be interchangeable with the original syntax. While it reduces visual burden, it hides many details, making it a cognitive burden for beginners. However, I must admit that syntactic sugar has its advantages in terms of code input. I plan to research how to develop an IDE plugin (I use VSCode) in my free time. This plugin will have two purposes: 1. In the input method, it will act like a shortcut, converting specific operators into syntactic transformations. 2. It will appropriately display syntactic sugar information next to the original code (I don't want to make any changes to the original code; the original code should display the most detailed details because it is the common language for everyone). Taking the previously proposed solution C as an example: ```java String s1 = "1"; String s2 = "1"; s1 === // After entering ===, it will automatically be converted to the following format s1.equals( `````` Another use case: ```java BigDecimal d1 = new BigDecimal("1"); BigDecimal d2 = new BigDecimal("2"); BigDecimal d3 = new BigDecimal("0"); d3 = d1 + // After entering +, it will automatically be converted to the following format d3 = d1.add( ``` Or maybe there is already such a plugin? That would be great! /* GET BETTER EVERY DAY */ -------------- next part -------------- An HTML attachment was scrubbed... URL: From eran at leshem.life Sun Nov 12 21:42:15 2023 From: eran at leshem.life (Eran Leshem) Date: Sun, 12 Nov 2023 23:42:15 +0200 Subject: String Templates: syntax question Message-ID: <02a101da15b1$1b0e2f00$512a8d00$@leshem.life> Hello, I'm delighted by the addition of String Templates to Java! I have a question about the syntax. The Alternatives section of the JEP gives great answers to most questions, but I was left with this one: Why is the backslash needed? In most languages, as you nicely listed, string templates are marked with either a template prefix or an embedded expression prefix. Why does Java require both the "." template prefix and the "\" embedded expression prefix? The Ensuring Safety section implies that the backslash's goal is to enable the detection of string templates with missing processors. Did I read that correctly? If so, I'd suggest documenting that explicitly. In addition, I'd like to raise the question whether the extra ceremony is warranted by that goal. Thanks Eran -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 13 00:10:28 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 12 Nov 2023 19:10:28 -0500 Subject: String Templates: syntax question In-Reply-To: <02a101da15b1$1b0e2f00$512a8d00$@leshem.life> References: <02a101da15b1$1b0e2f00$512a8d00$@leshem.life> Message-ID: On 11/12/2023 4:42 PM, Eran Leshem wrote: > > Hello, > > I?m delighted by the addition of String Templates to Java! > > I have a question about the syntax. The Alternatives section of the > JEP gives great answers to most questions, but I was left with this one: > > Why is the backslash needed? In most languages, as you nicely listed, > string templates are marked with either a template prefix or an > embedded expression prefix. Why does Java require both the > ?.? template prefix and the ?\? embedded expression prefix? > There were a number of reasons for this choice, which was made in the light of the many different choices other languages have made (and their pros and cons) and the consequences for _adding_ this as a feature to Java (as opposed to if it had been part of the language from day 1.) One proximate reason is uniformity and migration; Java programs are full of string literals today (which are sometimes used as templates for String::format and the like), and many of them have dollar signs already.? And a string literal / text block with _no_ embedded expressions can still be used in a template expression, and means the obvious thing, and this is both uniform and useful.? If all strings _except those with dollar signs_ were valid in template expressions, but dollar signs had to be escaped, this means migrating existing code to use template expressions forces the user to scan the entirety of their string (which could be many lines long) to search for dollar signs and escape them, or risk making a mistake.? That's terrible, and unnecessary. While it might be possible to rescue the ${blah} syntax if it were indeed great, in actually this syntax is terrible; we're all just so used to it that we've stopped seeing how awful it is.? The $ character is common in strings, which makes this error prone (using $ instead of \$ or however it would be escaped) and also means that strings with dollar signs are less readable.? A string literal is supposed to be a sequence of characters; while every string literal feature needs some sort of escape mechanism to handle non-printable characters, having two different escape mechanisms ($ for interpolation, \ for weird characters), each with their own special rules, is unnecessarily irregular.? It was not worth doing any work to rescue this syntax, just because it is familiar from some other languages.? We have an escape mechanism, which was easily extendible to this approach (and Swift's experience shows that the \{...} mechanism is perfectly usable.) I can sort of see how you might want to characterize the processor as a "template prefix", but it is not; it is something else.? The template expression syntax is built on the string literal / text block syntax, and adding extra complexity just to rescue a fatally flawed (albeit familiar) syntax would have been a bad choice. > The Ensuring Safety section implies that the backslash?s goal is to > enable the detection of string templates with missing processors. Did > I read that correctly? If so, I?d suggest documenting that explicitly. > In addition, I?d like to raise the question whether the extra ceremony > is warranted by that goal. > That was not the "goal"; it is merely one of its benefits.? The main reason to prefer backslash here is that strings _already have an escape mechanism_, and we should use the existing escape mechanism rather than inventing a new and different one.? This guarantees that existing strings can be used seamlessly with the new feature; it minimizes linguistic complexity and the activation energy of learning the language; and it reduces errors. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ella.ananeva at oracle.com Mon Nov 13 21:03:20 2023 From: ella.ananeva at oracle.com (Ella Ananeva) Date: Mon, 13 Nov 2023 21:03:20 +0000 Subject: java.lang.StringTemplate.RAW is not implicitly imported? Message-ID: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; and import static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Tue Nov 14 13:38:59 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Tue, 14 Nov 2023 13:38:59 +0000 Subject: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: References: Message-ID: Thank you for pointing that out. We will revise. On Nov 13, 2023, at 5:03?PM, Ella Ananeva wrote: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; andimport static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Nov 14 14:31:53 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 14 Nov 2023 15:31:53 +0100 (CET) Subject: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: References: Message-ID: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> For me, RAW does not need to be imported by default, it's uses is not that frequent, it's more like FMT than STR. regards, R?mi > From: "Jim Laskey" > To: "Ella Ananeva" > Cc: "amber-dev" > Sent: Tuesday, November 14, 2023 2:38:59 PM > Subject: Re: java.lang.StringTemplate.RAW is not implicitly imported? > Thank you for pointing that out. We will revise. >> On Nov 13, 2023, at 5:03 PM, Ella Ananeva wrote: >> Hi team, >> Reading the JEP 459 spec, I see this: >> The static members STR and RAW declared in the predefined interface >> StringTemplate , as if the declarations import static >> java.lang.StringTemplate.STR; and import static java.lang.StringTemplate.RAW; >> appeared at the beginning of each compilation unit immediately after any >> package declaration. >> As a result, the names of all implicitly imported classes, interfaces and static >> fields are available as simple names in every compilation unit. >> So, I assume this should work: >> package test ; >> public class Example { >> public static void main ( String argv[]) { >> int a = 1 ; >> StringTemplate raw = RAW. " \{ a}" ; >> } >> } >> But I get >> java:7: error: cannot find symbol >> StringTemplate raw = RAW."\{a + b}"; >> ^ >> symbol: variable RAW >> location: class Example >> java --version >> java 22-internal 2024-03-19 >> Java(TM) SE Runtime Environment (build >> 22-internal-2023-11-03-1839366.james.laskey.open) >> Java HotSpot(TM) 64-Bit Server VM (build >> 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) >> This code compiles if I add a static import import static >> java.lang.StringTemplate.RAW; >> STR is available through static import, so it?s only RAW that causes issues. >> Could it be a bug in JDK? >> Thank you, >> Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Tue Nov 14 14:33:32 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Tue, 14 Nov 2023 14:33:32 +0000 Subject: [External] : Re: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> References: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <14CF1034-2A2F-4000-A976-39678A3A5C01@oracle.com> To clarify, the spec is being revised to drop "import static java.lang.StringTemplate.RAW;?. On Nov 14, 2023, at 10:31?AM, Remi Forax wrote: For me, RAW does not need to be imported by default, it's uses is not that frequent, it's more like FMT than STR. regards, R?mi ________________________________ From: "Jim Laskey" To: "Ella Ananeva" Cc: "amber-dev" Sent: Tuesday, November 14, 2023 2:38:59 PM Subject: Re: java.lang.StringTemplate.RAW is not implicitly imported? Thank you for pointing that out. We will revise. On Nov 13, 2023, at 5:03?PM, Ella Ananeva wrote: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; andimport static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Nov 14 14:37:06 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Tue, 14 Nov 2023 15:37:06 +0100 (CET) Subject: [External] : Re: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: <14CF1034-2A2F-4000-A976-39678A3A5C01@oracle.com> References: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> <14CF1034-2A2F-4000-A976-39678A3A5C01@oracle.com> Message-ID: <1071852117.52751047.1699972626935.JavaMail.zimbra@univ-eiffel.fr> > From: "Jim Laskey" > To: "Remi Forax" > Cc: "Ella Ananeva" , "amber-dev" > > Sent: Tuesday, November 14, 2023 3:33:32 PM > Subject: Re: [External] : Re: java.lang.StringTemplate.RAW is not implicitly > imported? > To clarify, the spec is being revised to drop " import static > java.lang.StringTemplate.RAW;?. +1. Thanks, R?mi >> On Nov 14, 2023, at 10:31 AM, Remi Forax wrote: >> For me, >> RAW does not need to be imported by default, it's uses is not that frequent, >> it's more like FMT than STR. >> regards, >> R?mi >>> From: "Jim Laskey" >>> To: "Ella Ananeva" >>> Cc: "amber-dev" >>> Sent: Tuesday, November 14, 2023 2:38:59 PM >>> Subject: Re: java.lang.StringTemplate.RAW is not implicitly imported? >>> Thank you for pointing that out. We will revise. >>>> On Nov 13, 2023, at 5:03 PM, Ella Ananeva wrote: >>>> Hi team, >>>> Reading the JEP 459 spec, I see this: >>>> The static members STR and RAW declared in the predefined interface >>>> StringTemplate , as if the declarations import static >>>> java.lang.StringTemplate.STR; and import static java.lang.StringTemplate.RAW; >>>> appeared at the beginning of each compilation unit immediately after any >>>> package declaration. >>>> As a result, the names of all implicitly imported classes, interfaces and static >>>> fields are available as simple names in every compilation unit. >>>> So, I assume this should work: >>>> package test ; >>>> public class Example { >>>> public static void main ( String argv[]) { >>>> int a = 1 ; >>>> StringTemplate raw = RAW. " \{ a}" ; >>>> } >>>> } >>>> But I get >>>> java:7: error: cannot find symbol >>>> StringTemplate raw = RAW."\{a + b}"; >>>> ^ >>>> symbol: variable RAW >>>> location: class Example >>>> java --version >>>> java 22-internal 2024-03-19 >>>> Java(TM) SE Runtime Environment (build >>>> 22-internal-2023-11-03-1839366.james.laskey.open) >>>> Java HotSpot(TM) 64-Bit Server VM (build >>>> 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) >>>> This code compiles if I add a static import import static >>>> java.lang.StringTemplate.RAW; >>>> STR is available through static import, so it?s only RAW that causes issues. >>>> Could it be a bug in JDK? >>>> Thank you, >>>> Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Tue Nov 14 14:48:12 2023 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Tue, 14 Nov 2023 14:48:12 +0000 Subject: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: References: Message-ID: <143EAE4C-C992-44B0-A986-9599B5466FAF@oracle.com> Thanks for spotting this Ella. The spec at https://cr.openjdk.org/~gbierman/jep459/latest/ has been updated accordingly - only STR is implicitly imported. Gavin On 14 Nov 2023, at 13:38, Jim Laskey wrote: Thank you for pointing that out. We will revise. On Nov 13, 2023, at 5:03?PM, Ella Ananeva wrote: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; andimport static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From kan.izh at gmail.com Tue Nov 14 17:24:42 2023 From: kan.izh at gmail.com (Anatoly Kupriyanov) Date: Tue, 14 Nov 2023 17:24:42 +0000 Subject: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> References: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> Message-ID: Hm. Weird, it seems the class itself is imported by default. This code compiles just fine even without any import statements at all. It does not look right to me. But maybe I'm not using the latest version? StringTemplate st = null; On Tue, 14 Nov 2023 at 14:32, Remi Forax wrote: > For me, > RAW does not need to be imported by default, it's uses is not that > frequent, it's more like FMT than STR. > > regards, > R?mi > > ------------------------------ > > *From: *"Jim Laskey" > *To: *"Ella Ananeva" > *Cc: *"amber-dev" > *Sent: *Tuesday, November 14, 2023 2:38:59 PM > *Subject: *Re: java.lang.StringTemplate.RAW is not implicitly imported? > > Thank you for pointing that out. We will revise. > > On Nov 13, 2023, at 5:03?PM, Ella Ananeva wrote: > > Hi team, > Reading the JEP 459 spec, I see this: > > The static members STR and RAW declared in the predefined interface > StringTemplate, as if the declarations import static > java.lang.StringTemplate.STR; andimport static > java.lang.StringTemplate.RAW; appeared at the beginning of each > compilation unit immediately after any package declaration. > As a result, the names of all *implicitly imported* *classes, > interfaces and static fields* are available as simple names in every > compilation unit. > > So, I assume this should work: > > package test; > > public class Example { > > public static void main(String argv[]) { > > int a = 1; > StringTemplate raw = RAW."\{a}"; > } > } > > > But I get > > java:7: error: cannot find symbol > StringTemplate raw = RAW."\{a + b}"; > ^ > symbol: variable RAW > location: class Example > > java --version > java 22-internal 2024-03-19 > Java(TM) SE Runtime Environment (build > 22-internal-2023-11-03-1839366.james.laskey.open) > Java HotSpot(TM) 64-Bit Server VM (build > 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) > > This code compiles if I add a static import import static > java.lang.StringTemplate.RAW; > STR is available through static import, so it?s only RAW that causes > issues. > > Could it be a bug in JDK? > > Thank you, > Ella Ananeva > > > > -- WBR, Anatoly. -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Tue Nov 14 17:28:25 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Tue, 14 Nov 2023 17:28:25 +0000 Subject: [External] : Re: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: References: <267722147.52745235.1699972313868.JavaMail.zimbra@univ-eiffel.fr> Message-ID: <3BC2DBC3-04D3-4203-A101-43FFFC915E74@oracle.com> That is because StringTemplate is in the java.lang package which gets imported automatically: ?import java.lang.*?. On Nov 14, 2023, at 1:24?PM, Anatoly Kupriyanov wrote: Hm. Weird, it seems the class itself is imported by default. This code compiles just fine even without any import statements at all. It does not look right to me. But maybe I'm not using the latest version? StringTemplate st = null; On Tue, 14 Nov 2023 at 14:32, Remi Forax > wrote: For me, RAW does not need to be imported by default, it's uses is not that frequent, it's more like FMT than STR. regards, R?mi ________________________________ From: "Jim Laskey" > To: "Ella Ananeva" > Cc: "amber-dev" > Sent: Tuesday, November 14, 2023 2:38:59 PM Subject: Re: java.lang.StringTemplate.RAW is not implicitly imported? Thank you for pointing that out. We will revise. On Nov 13, 2023, at 5:03?PM, Ella Ananeva > wrote: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; andimport static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -- WBR, Anatoly. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ella.ananeva at oracle.com Tue Nov 14 17:41:22 2023 From: ella.ananeva at oracle.com (Ella Ananeva) Date: Tue, 14 Nov 2023 17:41:22 +0000 Subject: java.lang.StringTemplate.RAW is not implicitly imported? In-Reply-To: <143EAE4C-C992-44B0-A986-9599B5466FAF@oracle.com> References: <143EAE4C-C992-44B0-A986-9599B5466FAF@oracle.com> Message-ID: Thank you for addressing this issue! From: Gavin Bierman Date: Tuesday, November 14, 2023 at 6:48 AM To: Jim Laskey Cc: Ella Ananeva , amber-dev at openjdk.org Subject: Re: java.lang.StringTemplate.RAW is not implicitly imported? Thanks for spotting this Ella. The spec at https://cr.openjdk.org/~gbierman/jep459/latest/ has been updated accordingly - only STR is implicitly imported. Gavin On 14 Nov 2023, at 13:38, Jim Laskey wrote: Thank you for pointing that out. We will revise. On Nov 13, 2023, at 5:03?PM, Ella Ananeva wrote: Hi team, Reading the JEP 459 spec, I see this: The static members STR and RAW declared in the predefined interface StringTemplate, as if the declarations import static java.lang.StringTemplate.STR; andimport static java.lang.StringTemplate.RAW; appeared at the beginning of each compilation unit immediately after any package declaration. As a result, the names of all implicitly imported classes, interfaces and static fields are available as simple names in every compilation unit. So, I assume this should work: package test; public class Example { public static void main(String argv[]) { int a = 1; StringTemplate raw = RAW."\{a}"; } } But I get java:7: error: cannot find symbol StringTemplate raw = RAW."\{a + b}"; ^ symbol: variable RAW location: class Example java --version java 22-internal 2024-03-19 Java(TM) SE Runtime Environment (build 22-internal-2023-11-03-1839366.james.laskey.open) Java HotSpot(TM) 64-Bit Server VM (build 22-internal-2023-11-03-1839366.james.laskey.open, mixed mode, sharing) This code compiles if I add a static import import static java.lang.StringTemplate.RAW; STR is available through static import, so it?s only RAW that causes issues. Could it be a bug in JDK? Thank you, Ella Ananeva -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Wed Nov 15 02:34:21 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Tue, 14 Nov 2023 21:34:21 -0500 Subject: Want some official clarification on a quirk about pattern-matching for instanceof In-Reply-To: References: Message-ID: Bumping this one up since I didn't receive a response. On Fri, Nov 10, 2023 at 11:40?AM David Alayachew wrote: > Hello Amber Dev Team, > > Someone on StackOverflow raised an excellent question about > Pattern-Matching for instanceof, and I would like to get a response from > one of you to include in the answer. Here is the link. > > > https://stackoverflow.com/questions/77453336/instanceof-pattern-matching-in-java-not-compiling#77453336 > > To summarize, the book that they were reading (Java: The Complete > Reference, 12th Edition by Herbert Schildt) had the following quote. > > -----QUOTE_START---- (with minor modifications for readability) > > ```java > Number myOb = Integer.valueOf(9); > int count = 10; > > // vv---- Conditional AND Operator > if ( (count < 100) && myOb instanceof Integer iObj) > { > > iObj = count; > > } > ``` > > The above fragment compiles because the if block will execute only when > both sides of the && are true. Thus, the use of iObj in the if block is > valid. However, a compilation error will result if you tried to use the & > rather than the &&, as shown below. > > ```java > Number myOb = Integer.valueOf(9); > int count = 10; > > // v----- Bitwise Logical AND Operator > if ( (count < 100) & myOb instanceof Integer iObj) > { > > iObj = count; > > } > ``` > > In this case, the compiler cannot know whether or not iObj will be in > scope in the if block because the right side of the & will not necessarily > be evaluated. > > ----QUOTE_END---- > > When compiling the second example, it is exactly as the author says, we > get told that the variable may not necessarily be in scope. Here is the > error I get using OpenJDK 22 Early Access. > > ```java > $ java --version > openjdk 22-ea 2024-03-19 > OpenJDK Runtime Environment (build 22-ea+20-1570) > OpenJDK 64-Bit Server VM (build 22-ea+20-1570, mixed mode, sharing) > > $ javac --version > javac 22-ea > > $ cat abc.java > public class abc > { > > > public static void main(String[] args) > { > > Number myOb = Integer.valueOf(9); > > int count = 10; > > if ( (count < 100) & myOb instanceof Integer iObj ) > { > > iObj = count; > > } > > } > > } > > $ javac abc.java > abc.java:15: error: cannot find symbol > iObj = count; > ^ > symbol: variable iObj > location: class abc > 1 error > > ``` > > I feel like I have a very good idea of why this might be the case, but I > lack the terminology to put it into words correctly. Could someone help me > out? > > Thank you for your time and help! > David Alayachew > -------------- next part -------------- An HTML attachment was scrubbed... URL: From cay.horstmann at gmail.com Wed Nov 15 21:55:34 2023 From: cay.horstmann at gmail.com (Cay Horstmann) Date: Wed, 15 Nov 2023 22:55:34 +0100 Subject: Want some official clarification on a quirk about pattern-matching for instanceof In-Reply-To: References: Message-ID: <724c7af7-6710-415f-bd0d-624c3e565cd2@gmail.com> Here is my unofficial clarification. Herbert Schildt is wrong when he says that "the right side of the & will not necessarily be evaluated". It will be. The difference between && and & with boolean operands is that & will evaluate both operands, but && will not evaluate the right operand if the left one is false. You are right that in this context, it is plausible to think that iObj could have been declared. Nevertheless, why use the & operator? Herbert Schildt could/should tell his readers that there is no reason to use & other than with bit patterns. Admittedly it is legal to use & with boolean operands in the very uncommon situation of a side effect in the second operand. But that's subtle and may well be surprising to readers of your code. The Java Language Specification lays out rules to trace the scope of instanceof pattern definitions with && || ! and ?: operators. See https://docs.oracle.com/javase/specs/jls/se21/html/jls-6.html#jls-6.3. There are no rules for & and | operators. I think that's because they were never intended for boolean logic but only for bit patterns (and perhaps unfortunately, side effects in boolean conditions). And I wholeheartedly agree with the decision not to add that complexity to the language rules. My advice is to stay away from & and | for boolean operands. They were meant to fiddle with bits. For sure, don't use instanceof with those operators. With && and ||, and ! and ?:, the JLS rules are sensible and unsurprising. Cheers, Cay PS. Many years ago, a C FAQ had this statement (https://www.lysator.liu.se/c/c-faq/c-5.html): The cost [of the C standard document] is $130.00 from ANSI . . .the Annotated ANSI C Standard, with annotations by Herbert Schildt . . . sells in the U.S. for approximately $40. It has been suggested that the price differential between this work and the official standard reflects the value of the annotations. On 15/11/2023 03.34, David Alayachew wrote: > Bumping this one up since I didn't receive a response. > > On Fri, Nov 10, 2023 at 11:40?AM David Alayachew > wrote: > > Hello Amber Dev Team, > > Someone on StackOverflow raised an excellent question about Pattern-Matching for instanceof, and I would like to get a response from one of you to include in the answer. Here is the link. > > https://stackoverflow.com/questions/77453336/instanceof-pattern-matching-in-java-not-compiling#77453336 > > To summarize, the book that they were reading (Java: The Complete Reference, 12th Edition by Herbert Schildt) had the following quote. > > -----QUOTE_START---- (with minor modifications for readability) > > ```java > Number myOb = Integer.valueOf(9); > int count = 10; > > // ? ? ? ? ? ? ? ? vv---- Conditional AND Operator > if ( (count < 100) && myOb instanceof Integer iObj) > { > > ? ? iObj = count; > > } > ``` > > The above fragment compiles because the if block will execute only when both sides of the && are true. Thus, the use of iObj in the if block is valid. However, a compilation error will result if you tried to use the & rather than the &&, as shown below. > > ```java > Number myOb = Integer.valueOf(9); > int count = 10; > > // ? ? ? ? ? ? ? ? v----- Bitwise Logical AND Operator > if ( (count < 100) & myOb instanceof Integer iObj) > { > > ? ? iObj = count; > > } > ``` > > In this case, the compiler cannot know whether or not iObj will be in scope in the if block because the right side of the & will not necessarily be evaluated. > > ----QUOTE_END---- > > When compiling the second example, it is exactly as the author says, we get told that the variable may not necessarily be in scope. Here is the error I get using OpenJDK 22 Early Access. > > ```java > $ java --version > openjdk 22-ea 2024-03-19 > OpenJDK Runtime Environment (build 22-ea+20-1570) > OpenJDK 64-Bit Server VM (build 22-ea+20-1570, mixed mode, sharing) > > $ javac --version > javac 22-ea > > $ cat abc.java > public class abc > { > > > ? ? public static void main(String[] args) > ? ? { > > ? ? ? ? Number myOb = Integer.valueOf(9); > > ? ? ? ? int count = 10; > > ? ? ? ? if ( (count < 100) & myOb instanceof Integer iObj ) > ? ? ? ? { > > ? ? ? ? ? ? iObj = count; > > ? ? ? ? } > > ? ? } > > } > > $ javac abc.java > abc.java:15: error: cannot find symbol > ? ? ? ? ? ? ? ? iObj = count; > ? ? ? ? ? ? ? ? ^ > ? symbol: ? variable iObj > ? location: class abc > 1 error > > ``` > > I feel like I have a very good idea of why this might be the case, but I lack the terminology to put it into words correctly. Could someone help me out? > > Thank you for your time and help! > David Alayachew > -- Cay S. Horstmann | http://horstmann.com | mailto:cay at horstmann.com From mail at sebfisch.de Wed Nov 22 12:28:32 2023 From: mail at sebfisch.de (Sebastian Fischer) Date: Wed, 22 Nov 2023 13:28:32 +0100 Subject: Use cases for pattern matching Message-ID: Hello. Regarding the new features for pattern matching in JDK 21 I have some interesting use cases that highlight how they enable new ways to structure programs: https://github.com/sebfisch/java21-demo/wiki/Pattern-Matching Is this the right place to discuss them? The first example uses a file search program to illustrate how algebraic data types are useful in stream pipelines, especially in handling errors as values when using a functional programming style. The second example uses tree-structured data and shows how core ideas from functional programming, especially related to data traversal, can be integrated into Java, leveraging streams and other functional programming patterns. Interestingly, the operations for data traversal can be reused instead of implementing specialized variants for each new tree structure. I would be interested in what you expect about how the examples might change with future developments of Project Amber, especially regarding reconstruction expressions [1] and their relation to interfaces. For example, the interface interface Named { String name(); } can be implemented automatically by a record record Person(String name) implements Named {} because the record component matches the signature of the interface. It would be useful to be able to write named with { name = "New Name" } for all implementations of `Named` (not only `Person`) and I wonder how `Named` could in the future be adjusted accordingly such that records still implement it automatically. Best, Sebastian [1] https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Nov 22 16:06:48 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 22 Nov 2023 10:06:48 -0600 Subject: Stream confusion Message-ID: I have an API design question about Streams, but instead of asking the question outright I thought I'd ask it indirectly with a simple example. The Javadoc for Stream opens with this example: int sum = widgets.stream() .filter(w -> w.getColor() == RED) .mapToInt(w -> w.getWeight()) .sum(); OK, looks reasonable - we're computing the sum of the weights of all the red widgets. Here's the question: Is the following program deterministic? import java.awt.*; import java.util.function.*; import java.util.stream.*; import static java.awt.Color.*; public class Widget { private final Color color; private final int weight; public Widget(Color color, int weight) { this.color = color; this.weight = weight; } public Color getColor() { return this.color; } public int getWeight() { return this.weight; } public static int totalRedWeight(Widget... widgets) { return Stream.of(widgets) .filter(w -> w.getColor() == RED) .mapToInt(w -> w.getWeight()) .sum(); } // Test method public static void main(String[] args) { final Widget w1 = new Widget(RED, 123); final Widget w2 = new Widget(BLUE, 456); final int total = Widget.totalRedWeight(w1, w2); System.out.println("Total red weight = " + total); } } -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Nov 22 16:25:00 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 22 Nov 2023 10:25:00 -0600 Subject: Stream confusion In-Reply-To: References: Message-ID: Argh, sorry I pasted the wrong example. The Widget fields "color" and "weight" are supposed to NOT be final: @@ -5,8 +5,8 @@ public class Widget { - private final Color color; - private final int weight; + private Color color; + private int weight; public Widget(Color color, int weight) { this.color = color; The question remains the same - is the program deterministic? -Archie On Wed, Nov 22, 2023 at 10:06?AM Archie Cobbs wrote: > I have an API design question about Streams, but instead of asking the > question outright I thought I'd ask it indirectly with a simple example. > > The Javadoc for Stream opens with this example: > > int sum = widgets.stream() > .filter(w -> w.getColor() == RED) > .mapToInt(w -> w.getWeight()) > .sum(); > > OK, looks reasonable - we're computing the sum of the weights of all the > red widgets. > > Here's the question: Is the following program deterministic? > > import java.awt.*; > import java.util.function.*; > import java.util.stream.*; > import static java.awt.Color.*; > > public class Widget { > > private final Color color; > private final int weight; > > public Widget(Color color, int weight) { > this.color = color; > this.weight = weight; > } > > public Color getColor() { > return this.color; > } > > public int getWeight() { > return this.weight; > } > > public static int totalRedWeight(Widget... widgets) { > return Stream.of(widgets) > .filter(w -> w.getColor() == RED) > .mapToInt(w -> w.getWeight()) > .sum(); > } > > // Test method > > public static void main(String[] args) { > final Widget w1 = new Widget(RED, 123); > final Widget w2 = new Widget(BLUE, 456); > final int total = Widget.totalRedWeight(w1, w2); > System.out.println("Total red weight = " + total); > } > } > > -Archie > > -- > Archie L. Cobbs > -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From numeralnathan at gmail.com Wed Nov 22 17:13:02 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Wed, 22 Nov 2023 09:13:02 -0800 Subject: Stream confusion In-Reply-To: References: Message-ID: It is not only deterministic but also JIT (or an advanced version) could reduce this code to the following single line in main(). System.out.println("Total red weight = 123"); Since there are no assignments to the Widget fields after construction, they are effectively final. I wouldn't be surprised if JIT assumes that they are final. Also, there is no need to put final in the main() body since these values are effectively final. (You can lookup effectively final.) I feel like you might be confusing final with deterministic. Final requires the value to not change. Deterministic requires that a given input always produces the same output. The variables can change values throughout the program's computation but the program will still be deterministic if the same input gives the same output. A nondeterministic program would use SecureRandom.next___() or some other truly random source during its computation. On Wed, Nov 22, 2023 at 8:25?AM Archie Cobbs wrote: > Argh, sorry I pasted the wrong example. The Widget fields "color" and > "weight" are supposed to NOT be final: > > @@ -5,8 +5,8 @@ > > public class Widget { > > - private final Color color; > - private final int weight; > + private Color color; > + private int weight; > > public Widget(Color color, int weight) { > this.color = color; > > The question remains the same - is the program deterministic? > > -Archie > > On Wed, Nov 22, 2023 at 10:06?AM Archie Cobbs > wrote: > >> I have an API design question about Streams, but instead of asking the >> question outright I thought I'd ask it indirectly with a simple example. >> >> The Javadoc for Stream opens with this example: >> >> int sum = widgets.stream() >> .filter(w -> w.getColor() == RED) >> .mapToInt(w -> w.getWeight()) >> .sum(); >> >> OK, looks reasonable - we're computing the sum of the weights of all the >> red widgets. >> >> Here's the question: Is the following program deterministic? >> >> import java.awt.*; >> import java.util.function.*; >> import java.util.stream.*; >> import static java.awt.Color.*; >> >> public class Widget { >> >> private final Color color; >> private final int weight; >> >> public Widget(Color color, int weight) { >> this.color = color; >> this.weight = weight; >> } >> >> public Color getColor() { >> return this.color; >> } >> >> public int getWeight() { >> return this.weight; >> } >> >> public static int totalRedWeight(Widget... widgets) { >> return Stream.of(widgets) >> .filter(w -> w.getColor() == RED) >> .mapToInt(w -> w.getWeight()) >> .sum(); >> } >> >> // Test method >> >> public static void main(String[] args) { >> final Widget w1 = new Widget(RED, 123); >> final Widget w2 = new Widget(BLUE, 456); >> final int total = Widget.totalRedWeight(w1, w2); >> System.out.println("Total red weight = " + total); >> } >> } >> >> -Archie >> >> -- >> Archie L. Cobbs >> > > > -- > Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Nov 22 17:52:06 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 22 Nov 2023 11:52:06 -0600 Subject: Stream confusion In-Reply-To: References: Message-ID: On Wed, Nov 22, 2023 at 11:13?AM Nathan Reynolds wrote: > It is not only deterministic but also JIT (or an advanced version) could > reduce this code to the following single line in main(). > > System.out.println("Total red weight = 123"); > > Since there are no assignments to the Widget fields after construction, > they are effectively final. I wouldn't be surprised if JIT assumes that > they are final. Also, there is no need to put final in the main() body > since these values are effectively final. (You can lookup effectively > final.) > OK I believe you that in the current implementation of the JDK, the behavior is deterministic. But as a developer trying to write bug-free code, I can only assume what is published in the documented API. Implementation details about the runtime I happen to be using are not relevant to proving the statement "This Java program is always deterministic". And if I'm limited to what's published in the API for Stream, etc., how am I supposed to prove to myself that the program is deterministic? To do that, I would have to assume (for example) that Stream.filter() will always execute in the current thread, because otherwise the writes to the non-final fields are not guaranteed to be visible to other threads. But this is not guaranteed to be true in the Stream API docs. In fact, they explicitly state that this would be an unsafe assumption: Note also that attempting to access mutable state from behavioral > parameters presents you with a bad choice with respect to safety and > performance; if you do not synchronize access to that state, you have a > data race and therefore your code is broken > To make the example program correct based on the documented API, we would have to add synchronization around the construction of the Widgets and pair that with synchronization around the lambdas passed to filter() and mapToInt(). Of course in the real world nobody does that. As a result, my contention is that there is a giant universe of code out there that, just like my example, executes a Stream pipeline on data that is constructed/prepared in the current thread but not guaranteed to be safely published, and where the pipeline contains unsynchronized "behavioral parameters" that access that data. Any such code is therefore not guaranteed to be deterministic! The fact that the code works *today* is nice, but it doesn't change the fact that all of this code is just a giant ticking time bomb in case the implementation ever changes (project loom anyone?) Or, you might say "Well, in practice non-parallel streams are always executed in the local thread and I'm sure they'll be that way for a long time". Great! If that's our stance, then this should be made official and documented in the API: "Non-parallel streams always execute in the current thread". Right now it seems like we have the worst of both worlds... -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From numeralnathan at gmail.com Wed Nov 22 18:24:04 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Wed, 22 Nov 2023 10:24:04 -0800 Subject: Stream confusion In-Reply-To: References: Message-ID: If you use a parallel stream, I would guess the code would still be deterministic. The parallel stream has to safely confer the references from the main thread to the helper threads. This requires some sort of synchronization. By safely conferring the references, the field values in the objects get the benefit of the synchronization too. I haven't played with Loom threads yet. From what I have read, it doesn't sound like Loom threads change the functional behavior of the program. Loom threads only change the performance behavior. On Wed, Nov 22, 2023 at 9:52?AM Archie Cobbs wrote: > > On Wed, Nov 22, 2023 at 11:13?AM Nathan Reynolds > wrote: > >> It is not only deterministic but also JIT (or an advanced version) could >> reduce this code to the following single line in main(). >> >> System.out.println("Total red weight = 123"); >> >> Since there are no assignments to the Widget fields after construction, >> they are effectively final. I wouldn't be surprised if JIT assumes that >> they are final. Also, there is no need to put final in the main() body >> since these values are effectively final. (You can lookup effectively >> final.) >> > > OK I believe you that in the current implementation of the JDK, the > behavior is deterministic. > > But as a developer trying to write bug-free code, I can only assume what > is published in the documented API. > > Implementation details about the runtime I happen to be using are not > relevant to proving the statement "This Java program is always > deterministic". > > And if I'm limited to what's published in the API for Stream, etc., how am > I supposed to prove to myself that the program is deterministic? > > To do that, I would have to assume (for example) that Stream.filter() > will always execute in the current thread, because otherwise the writes to > the non-final fields are not guaranteed to be visible to other threads. > > But this is not guaranteed to be true in the Stream API docs. In fact, > they explicitly state that this would be an unsafe assumption: > > Note also that attempting to access mutable state from behavioral >> parameters presents you with a bad choice with respect to safety and >> performance; if you do not synchronize access to that state, you have a >> data race and therefore your code is broken >> > > To make the example program correct based on the documented API, we would > have to add synchronization around the construction of the Widgets and pair > that with synchronization around the lambdas passed to filter() and > mapToInt(). > > Of course in the real world nobody does that. As a result, my contention > is that there is a giant universe of code out there that, just like my > example, executes a Stream pipeline on data that is constructed/prepared in > the current thread but not guaranteed to be safely published, and where the > pipeline contains unsynchronized "behavioral parameters" that access that > data. > > Any such code is therefore not guaranteed to be deterministic! > > The fact that the code works *today* is nice, but it doesn't change the > fact that all of this code is just a giant ticking time bomb in case the > implementation ever changes (project loom anyone?) > > Or, you might say "Well, in practice non-parallel streams are always > executed in the local thread and I'm sure they'll be that way for a long > time". > > Great! If that's our stance, then this should be made official and > documented in the API: "Non-parallel streams always execute in the current > thread". > > Right now it seems like we have the worst of both worlds... > > -Archie > > -- > Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From org.openjdk at io7m.com Wed Nov 22 19:44:21 2023 From: org.openjdk at io7m.com (Mark Raynsford) Date: Wed, 22 Nov 2023 19:44:21 +0000 Subject: Stream confusion In-Reply-To: References: Message-ID: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> On Wed, 2023-11-22 at 10:24 -0800, Nathan Reynolds wrote: > > I haven't played with Loom threads yet.? From what I have read, it > doesn't > sound like Loom threads change the functional behavior of the > program. > Loom threads only change the performance behavior. They actually do. I was surprised by (and bitten by this): private final Map data; void unsafe() { this.data.put("x", "y"); System.in.read(); this.data.put("x", "z"); } The above unsafe() method is safe when called on a single platform thread. This is just normal "thread confinement" of the kind we've been using for years. The unsafe() method isn't safe when called by a single virtual thread. Why? Because the call to System.in.read() will cause the virtual thread to yield, and it may be resumed on a different _carrier_ thread after the read() call finishes.?Nothing ensures those calls to Map.put() will result in safe publication. It just means that code that was safe to call on a single platform thread that assumed thread confinement (and so didn't synchronize its own private data) will break in perhaps surprising ways when called on a single virtual thread. -- Mark Raynsford | https://www.io7m.com From ron.pressler at oracle.com Wed Nov 22 19:46:09 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Wed, 22 Nov 2023 19:46:09 +0000 Subject: Stream confusion In-Reply-To: References: Message-ID: > On 22 Nov 2023, at 17:52, Archie Cobbs wrote: > > To do that, I would have to assume (for example) that Stream.filter() will always execute in the current thread, because otherwise the writes to the non-final fields are not guaranteed to be visible to other threads. I don?t think you need to assume that. *Which* writes you?re afraid may not be visible? All writes that ?happen before? the call to the stream?s terminal operation should be visible regardless of which threads are used. For example, you can generally submit tasks with non-final fields to ExecutorServices backed by thread pools because the writes to the fields on the submitting thread ?happen before? the submission, and the submission ?happens before? the execution of the task on the worker thread. Of course, you may get races if the submitting thread tries to mutate the fields after the submission of the task. > > But this is not guaranteed to be true in the Stream API docs. In fact, they explicitly state that this would be an unsafe assumption: ... > I think you?re reading ?mutable state? as ?non-final fields?, but the intent ? as I read it ? is "state that is mutated concurrently with the stream?s operation." ? Ron From ron.pressler at oracle.com Wed Nov 22 19:50:03 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Wed, 22 Nov 2023 19:50:03 +0000 Subject: Stream confusion In-Reply-To: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> References: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> Message-ID: > On 22 Nov 2023, at 19:44, Mark Raynsford wrote: > Nothing ensures those calls to Map.put() will result in safe publication. The JMM does, and if virtual threads break it then that?s a bug. What guides visibility in Java isn?t thread identity but the JMM and its happens-before relationship. It doesn?t matter which OS thread performs an operation. What matters is that the JMM?s happens-before relationships are preserved. Anyway, I don?t think any of this discussion belongs on amber-dev (I should have pointed it out earlier). Discussions about streams and their JMM guarantees belong in core-libs-dev. Discussions about virtual threads belong on loom-dev. ? Ron From numeralnathan at gmail.com Wed Nov 22 20:19:09 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Wed, 22 Nov 2023 12:19:09 -0800 Subject: Stream confusion In-Reply-To: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> References: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> Message-ID: When the virtual thread hits the read(), it blocks. The virtual thread's call stack is copied off the carrier thread's stack. When the virtual thread unblocks, another carrier thread copies the virtual thread's call stack back to the carrier thread's stack. Both of these operations require synchronization (or happens before) to ensure the virtual thread's stack is safely passed from one carrier thread to another carrier thread. This synchronization ensures the passing of "this" from one carrier thread to another carrier thread is safe. Hence, the unsafe() method is safe with regards to a virtual thread executing on several different carrier threads. unsafe() is not safe from multiple virtual threads calling it on the same "this". unsafe() is not safe from multiple OS threads calling it on the same "this". On Wed, Nov 22, 2023 at 11:44?AM Mark Raynsford wrote: > On Wed, 2023-11-22 at 10:24 -0800, Nathan Reynolds wrote: > > > > I haven't played with Loom threads yet. From what I have read, it > > doesn't > > sound like Loom threads change the functional behavior of the > > program. > > Loom threads only change the performance behavior. > > They actually do. I was surprised by (and bitten by this): > > private final Map data; > > void unsafe() > { > this.data.put("x", "y"); > System.in.read(); > this.data.put("x", "z"); > } > > The above unsafe() method is safe when called on a single platform > thread. This is just normal "thread confinement" of the kind we've > been using for years. The unsafe() method isn't safe when called by > a single virtual thread. Why? Because the call to System.in.read() > will cause the virtual thread to yield, and it may be resumed on > a different _carrier_ thread after the read() call finishes. Nothing > ensures those calls to Map.put() will result in safe publication. > > It just means that code that was safe to call on a single platform > thread that assumed thread confinement (and so didn't synchronize its > own private data) will break in perhaps surprising ways when called on > a single virtual thread. > > -- > Mark Raynsford | https://www.io7m.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Nov 22 20:52:45 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 22 Nov 2023 14:52:45 -0600 Subject: Stream confusion In-Reply-To: References: Message-ID: On Wed, Nov 22, 2023 at 1:46?PM Ron Pressler wrote: > For example, you can generally submit tasks with non-final fields to > ExecutorServices backed by thread pools because the writes to the fields on > the submitting thread ?happen before? the submission, and the submission > ?happens before? the execution of the task on the worker thread. Thanks - I was missing that part. Although the docs don't use the "happens-before" terminology they do say this: For well-behaved stream sources, the source can be modified before the > terminal operation commences and those modifications will be reflected in > the covered elements. > So we would just need to know that our streams are "well behaved"... the docs say: All the streams returned from JDK collections, and most other JDK classes, > are well-behaved in this manner; for streams generated by other libraries, > see Low-level stream construction > > for requirements for building well-behaved streams > Hmm, that still leaves the door open for "poorly behaved" Streams. It would be nice if instead "well-behaved" were an explicit requirement. I don?t think any of this discussion belongs on amber-dev > Sorry about that, I'll stop for now. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From org.openjdk at io7m.com Thu Nov 23 12:07:58 2023 From: org.openjdk at io7m.com (Mark Raynsford) Date: Thu, 23 Nov 2023 12:07:58 +0000 Subject: Stream confusion In-Reply-To: References: <50ac74a7b1a8ef2d8820d8a4ddeff4dd39d148ef.camel@io7m.com> Message-ID: <6d9c4747cda1f19915931466058f2d5d455dd5da.camel@io7m.com> On Wed, 2023-11-22 at 12:19 -0800, Nathan Reynolds wrote: > This synchronization ensures the passing of "this" from one carrier thread to another carrier thread is safe. I'm happy to be wrong about this. I even had a reproducer which, it turns out, wasn't reproducing what I thought it was reproducing. :) I did have more than one moment of "surely it can't actually be working this way?" before the original email. -- Mark Raynsford | https://www.io7m.com From donolwenn at gmail.com Thu Nov 23 23:11:46 2023 From: donolwenn at gmail.com (Nolwenn Doucet) Date: Fri, 24 Nov 2023 00:11:46 +0100 Subject: Switch expression with enum and when clause Message-ID: <93c28a33-55ab-4c33-b244-be4e722f6820@gmail.com> Hello, I play with switch expression in java 21 and try to use a when clause on enum values to check a predicate on a class field and sadly it?s not possible. Will it be possible to do this in a future release or it?s irrelevant use of when clause? Nolwenn public class Rental { ? private final Movie movie; ? private final int daysRented; ? public Rental(Movie movie, int daysRented) { ??? this.movie = movie; ??? this.daysRented = daysRented; ? } ? int renterPoints() { ?? return switch(movie.type()) { ????? case MovieType.NEW_RELEASE when daysRented > 1 -> 2; ????? case MovieType.NEW_RELEASE, MovieType.CHILDRENS, MovieType.REGULAR -> 1; ??? }; ? } } public record Movie(String title, MovieType type) {} public enum MovieType { ? CHILDRENS, NEW_RELEASE, REGULAR; } javac Rental.java Rental.java:22: error: : or -> expected ? case MovieType.NEW_RELEASE when daysRented > 1 -> 2; ???????????????????????????????????? ^ Rental.java:22: error: not a statement ? case MovieType.NEW_RELEASE when daysRented > 1 -> 2; ???????????????????????????????????????????????? ^ Rental.java:22: error: ';' expected ? case MovieType.NEW_RELEASE when daysRented > 1 -> 2; From brian.goetz at oracle.com Mon Nov 27 16:54:58 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 27 Nov 2023 16:54:58 +0000 Subject: Use cases for pattern matching In-Reply-To: References: Message-ID: Reconstruction expressions are built on matching pairs of constructors and deconstruction patterns. We can put deconstruction patterns in interfaces (Map.Entry is a prime example), but not constructors. At some point we may bring the notion of factory into the language more formally, in which case we could pair deconstruction patterns with either constructors or factories, and interfaces can have factories, so we might be able to get to something like what you?re asking about in the future, but currently that?s quite a few steps down the road. Without some code in the interface for ?how do I make a new one?, reconstruction expressions don?t really make sense. It would not be reasonable to, say, look at the dynamic type of the receiver and try to guess how to make a new one based on that; a reconstruction expression should be given clear semantics based on the static types involved. So for the time being, your example would be over the horizon of what reconstruction expressions could do ? because it?s not even obvious what they _should_ do in this situation. On Nov 22, 2023, at 7:28 AM, Sebastian Fischer > wrote: Hello. Regarding the new features for pattern matching in JDK 21 I have some interesting use cases that highlight how they enable new ways to structure programs: https://github.com/sebfisch/java21-demo/wiki/Pattern-Matching Is this the right place to discuss them? The first example uses a file search program to illustrate how algebraic data types are useful in stream pipelines, especially in handling errors as values when using a functional programming style. The second example uses tree-structured data and shows how core ideas from functional programming, especially related to data traversal, can be integrated into Java, leveraging streams and other functional programming patterns. Interestingly, the operations for data traversal can be reused instead of implementing specialized variants for each new tree structure. I would be interested in what you expect about how the examples might change with future developments of Project Amber, especially regarding reconstruction expressions [1] and their relation to interfaces. For example, the interface interface Named { String name(); } can be implemented automatically by a record record Person(String name) implements Named {} because the record component matches the signature of the interface. It would be useful to be able to write named with { name = "New Name" } for all implementations of `Named` (not only `Person`) and I wonder how `Named` could in the future be adjusted accordingly such that records still implement it automatically. Best, Sebastian [1] https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html -------------- next part -------------- An HTML attachment was scrubbed... URL: From ogdeeboii3 at gmail.com Thu Nov 23 06:08:05 2023 From: ogdeeboii3 at gmail.com (daniel Thompson) Date: Thu, 23 Nov 2023 00:08:05 -0600 Subject: hg: amber/amber: disallow guards in records, it was good while it lasted :( Message-ID: http://www.sqlfiddle.com/#!2/c0eba/1public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } -------------- next part -------------- An HTML attachment was scrubbed... URL: From sivakumar.gurusamy at oracle.com Mon Nov 27 12:38:35 2023 From: sivakumar.gurusamy at oracle.com (Sivakumar Gurusamy) Date: Mon, 27 Nov 2023 12:38:35 +0000 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification Message-ID: Hello All, The JEP 445 (Unnamed Classes and Instance Main Methods (First Preview)) didn't define class name generated for unnamed classes that made difficult to develop JCK21 tests. Thanks to the change in JEP 463 (Implicitly Declared Classes and Instance Main Methods (Second Preview)). Now more JCK22 test can be developed and run. But some difficulty remain: As per JEP 463 class name is "determined by the host system". The spec hints typical algorithm how the class name can be generated. But what JCK tests can do in other (non-typical) cases ? A question: Can a host generate arbitrary class name indeterministically/randomly? If the generated class name can't be determined then execution step has to be skipped thus weakening tests. Please suggest. Thank you, JCK Team -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Nov 27 17:02:01 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 27 Nov 2023 17:02:01 +0000 Subject: Switch expression with enum and when clause In-Reply-To: <93c28a33-55ab-4c33-b244-be4e722f6820@gmail.com> References: <93c28a33-55ab-4c33-b244-be4e722f6820@gmail.com> Message-ID: <89B04F05-CA32-46F5-8006-B39F64C92F93@oracle.com> Currently, there are two kinds of cases: constant cases and pattern cases. In the long term, we would like to make constant cases go away, and turn these into constant patterns ? at which point the restriction on guards will be lifted. > On Nov 23, 2023, at 6:11 PM, Nolwenn Doucet wrote: > > Hello, > > I play with switch expression in java 21 and try to use a when clause on enum values to check > a predicate on a class field and sadly it?s not possible. > > Will it be possible to do this in a future release or it?s irrelevant use of when clause? > > Nolwenn > > public class Rental { > > private final Movie movie; > private final int daysRented; > > public Rental(Movie movie, int daysRented) { > this.movie = movie; > this.daysRented = daysRented; > } > > int renterPoints() { > return switch(movie.type()) { > case MovieType.NEW_RELEASE when daysRented > 1 -> 2; > case MovieType.NEW_RELEASE, MovieType.CHILDRENS, MovieType.REGULAR -> 1; > }; > } > } > > public record Movie(String title, MovieType type) {} > > public enum MovieType { > CHILDRENS, NEW_RELEASE, REGULAR; > } > > javac Rental.java > Rental.java:22: error: : or -> expected > case MovieType.NEW_RELEASE when daysRented > 1 -> 2; > ^ > Rental.java:22: error: not a statement > case MovieType.NEW_RELEASE when daysRented > 1 -> 2; > ^ > Rental.java:22: error: ';' expected > case MovieType.NEW_RELEASE when daysRented > 1 -> 2; From brian.goetz at oracle.com Mon Nov 27 17:26:41 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 27 Nov 2023 17:26:41 +0000 Subject: Fwd: [JEP 440] Question regarding removing support for record patterns appearing in the header of an enhanced for statement References: Message-ID: <26AA7BB7-26B8-4B3E-9D90-BC461D3C0116@oracle.com> The following was received on amber-spec-comments. The answer is quite simple: we didn?t think that this sub-feature was ready. As we look ahead at pattern-related features to come, it is clear that there are interactions with several of them (especially imperative matching), and it made sense to co-design those feature so as not to create a new constraint that those would have to be compatible with. Begin forwarded message: From: "Spaendonck, Flip van" > Subject: [JEP 440] Question regarding removing support for record patterns appearing in the header of an enhanced for statement Date: November 22, 2023 at 5:40:49 AM EST To: "amber-spec-comments at openjdk.org" > Dear Amber Expert Group member, I am a PhD candidate at Eindhoven University of Technology doing research into formally proving the correctness of automated restructurings of large legacy codebases. The features that have come with JDK21 have been very useful when it comes to quickly delivering robust code, especially JEP 440 and its sibling JEP 441. However, in JEP 440, it is noted that ?the main change since the second preview is to remove support for record patterns appearing in the header of an enhanced for statement.?. I have tried my best to find the rationale behind this decision, but I can not find any comments on this on the internet, nor am I able to come up with a convincing argument, besides time/labor constraints, myself. I certainly do not intend to start an argument on this decision, I am just hoping that perhaps one of the expert group members could give some explanation as to why it was decided to drop this feature. With kind regards, Flip van Spaendonck -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Mon Nov 27 18:20:29 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Mon, 27 Nov 2023 18:20:29 +0000 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: References: Message-ID: > On 27 Nov 2023, at 12:38, Sivakumar Gurusamy wrote: > > Hello All, > The JEP 445 (Unnamed Classes and Instance Main Methods (First Preview)) didn't define class name generated for unnamed classes that made difficult to develop JCK21 tests. > Thanks to the change in JEP 463 (Implicitly Declared Classes and Instance Main Methods (Second Preview)). Now more JCK22 test can be developed and run. > But some difficulty remain: As per JEP 463 class name is "determined by the host system". > The spec hints typical algorithm how the class name can be generated. > But what JCK tests can do in other (non-typical) cases ? > A question: Can a host generate arbitrary class name indeterministically/randomly? > If the generated class name can't be determined then execution step has to be skipped thus weakening tests. > Please suggest. > Thank you, > JCK Team Hi. Let me first answer your question with a question: As the JEP and spec change state, the host-selected class name cannot and must not be used by Java source code; in that case, what tests specifically would you like to write that an arbitrarily chosen name could complicate? Because the class name cannot be used in source code, there is nothing you can do with the class other than launch it, i.e. invoke its selected main method as the program?s entry point. The assumption is that the chosen class name is either irrelevant for the launching process (when the source file is launched directly in source code mode, where the launcher is given the name of the .java file rather than the class name) or (possibly implicitly) made known to the user by the compiler; i.e. when you compile Foo.java, javac will produce a class file (typically Foo.class and perhaps others) that will then be used when launching the program, either directly on the command line or in the Main-Class attribute of an executable JAR?s manifest. ? Ron From leonid.arbouzov at oracle.com Mon Nov 27 20:25:56 2023 From: leonid.arbouzov at oracle.com (leonid.arbouzov at oracle.com) Date: Mon, 27 Nov 2023 12:25:56 -0800 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: References: Message-ID: Hi Ron, The JCK may not launch the source file directly because JEP 330 [1] has JDK scope and not Java SE scope (i.e. Java implementations are not required to support the feature "Launch Single-File Source-Code Programs"). How the JCK can launch a test class not knowing its name in an implementation-independent manner? Thanks, Leonid JCK Team [1] https://openjdk.org/jeps/330 On 11/27/23 10:20 AM, Ron Pressler wrote: > >> On 27 Nov 2023, at 12:38, Sivakumar Gurusamy >> wrote: >> >> Hello All, >> The JEP 445 (Unnamed Classes and Instance Main Methods (First >> Preview)) didn't define class name generated for unnamed classes that >> made difficult to develop JCK21 tests. >> Thanks to the change in JEP 463 (Implicitly Declared Classes and >> Instance Main Methods (Second Preview)). Now more JCK22 test can be >> developed and run. >> But some difficulty remain: As per JEP 463 class name is "determined >> by the host system". >> The spec hints typical algorithm how the class name can be generated. >> But what JCK tests can do in other (non-typical) cases ? >> A question: Can a host generate arbitrary class name >> indeterministically/randomly? >> If the generated class name can't be determined then execution step >> has to be skipped thus weakening tests. >> Please suggest. >> Thank you, >> JCK Team > Hi. > > Let me first answer your question with a question: As the JEP and spec > change state, the host-selected class name cannot and must not be used > by Java source code; in that case, what tests specifically would you > like to write that an arbitrarily chosen name could complicate? > > Because the class name cannot be used in source code, there is nothing > you can do with the class other than launch it, i.e. invoke its > selected main method as the program?s entry point. > > The assumption is that the chosen class name is either irrelevant for > the launching process (when the source file is launched directly in > source code mode, where the launcher is given the name of the .java > file rather than the class name) or (possibly implicitly) made known > to the user by the compiler; i.e. when you compile Foo.java, javac > will produce a class file (typically Foo.class and perhaps others) > that will then be used when launching the program, either directly on > the command line or in the Main-Class attribute of an executable JAR?s > manifest. > > ? Ron From ron.pressler at oracle.com Tue Nov 28 12:22:13 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 28 Nov 2023 12:22:13 +0000 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: References: Message-ID: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> > On 27 Nov 2023, at 20:25, Leonid Arbuzov wrote: > > > How the JCK can launch a test class not knowing its name in an implementation-independent manner? > Is launching *any* Java program specified SE even if you do know the name of its main class? For example, JLS ?12.1.4 specifies the `main` method but doesn?t specify how the main class is launched. Does it matter, then, that the chosen name for the main class is implementation-specific given that launching the main class is also implementation-specific? Perhaps the best way to test implicit classes, then, is from *within* the implicit class itself. Like any other main class, it is launched by some implementation-specific mechanism, but once you?re in it, everything is known. You can then get the chosen class name with `this.getClass()?`. ? Ron From mail at sebfisch.de Tue Nov 28 12:49:24 2023 From: mail at sebfisch.de (Sebastian Fischer) Date: Tue, 28 Nov 2023 13:49:24 +0100 Subject: Use cases for pattern matching In-Reply-To: References: Message-ID: > We can put deconstruction patterns in interfaces (Map.Entry is a prime > example), but not constructors. At some point we may bring the notion of > factory into the language more formally, in which case we could pair > deconstruction patterns with either constructors or factories, and > interfaces can have factories, so we might be able to get to something like > what you?re asking about in the future, but currently that?s quite a few > steps down the road. > Indeed. I saw the section on interfaces in the document [1] linked in your post mentioned earlier. But it seems like the presented factory and deconstructor come with implementations inside the interface, whereas I think my use case would need something like "has a constructor and a corresponding deconstructor that include the names ..." to be expressible in an interface. Different implementations of such an interface could implement constructors and deconstructors in different ways and potentially with more parameters as required by the interface. For example in addition to the shown Person record implementing the Named interface we could have: record Ingredient(String name, int grams) implements Named and for my original use case (generic data traversal) it would be useful if I could somehow define the interface Named in such a way that both Person and Ingredient implement it automatically (because both records have a canonical constructor and corresponding deconstructor that include the variable "name".) Instead of capturing the meaning of reconstruction expressions by using constructors (or factories) and deconstructors, a more specialized way to define such interfaces could be as follows: interface Named { __components(String name, /* potentially more like in record declarations */); } Such an interface declaration could mean that implementations allow reconstruction expressions with assignments to the variable "name" and a corresponding getter. I realize that support for defining such interfaces is far ahead and may never be available. I like to point out that such functionality fits records (maybe other classes with corresponding constructors and deconstructors too) and would be useful for generic data traversal (and potentially other use cases.) To complete the example given here, I'd like to be able to define: static N withNewName(N named, String newName) { return named with { name = newName }; } and be able to use it for both Person and Ingredient. The hypothetical interface declaration above seems to cover this use case. I think I have a clear understanding of what it would mean but may be missing aspects I'm currently unaware of. [1] https://github.com/openjdk/amber-docs/blob/master/eg-drafts/reconstruction-records-and-classes.md Without some code in the interface for ?how do I make a new one?, > reconstruction expressions don?t really make sense. It would not be > reasonable to, say, look at the dynamic type of the receiver and try to > guess how to make a new one based on that; a reconstruction expression > should be given clear semantics based on the static types involved. So for > the time being, your example would be over the horizon of what > reconstruction expressions could do ? because it?s not even obvious what > they _should_ do in this situation. > > On Nov 22, 2023, at 7:28 AM, Sebastian Fischer wrote: > > Hello. > > Regarding the new features for pattern matching in JDK 21 I have some > interesting use cases that highlight how they enable new ways to structure > programs: > > https://github.com/sebfisch/java21-demo/wiki/Pattern-Matching > > Is this the right place to discuss them? > > The first example uses a file search program to illustrate how algebraic > data types are useful in stream pipelines, especially in handling errors as > values when using a functional programming style. The second example uses > tree-structured data and shows how core ideas from functional programming, > especially related to data traversal, can be integrated into Java, > leveraging streams and other functional programming patterns. > Interestingly, the operations for data traversal can be reused instead of > implementing specialized variants for each new tree structure. > > I would be interested in what you expect about how the examples might > change with future developments of Project Amber, especially regarding > reconstruction expressions [1] and their relation to interfaces. > > For example, the interface > > interface Named { String name(); } > > can be implemented automatically by a record > > record Person(String name) implements Named {} > > because the record component matches the signature of the interface. > > It would be useful to be able to write > > named with { name = "New Name" } > > for all implementations of `Named` (not only `Person`) and I wonder how > `Named` could in the future be adjusted accordingly such that records still > implement it automatically. > > Best, > Sebastian > > [1] > https://mail.openjdk.org/pipermail/amber-spec-experts/2022-June/003461.html > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Tue Nov 28 14:54:08 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Tue, 28 Nov 2023 15:54:08 +0100 (CET) Subject: Switch expression with enum and when clause In-Reply-To: <89B04F05-CA32-46F5-8006-B39F64C92F93@oracle.com> References: <93c28a33-55ab-4c33-b244-be4e722f6820@gmail.com> <89B04F05-CA32-46F5-8006-B39F64C92F93@oracle.com> Message-ID: <1837696182.66359140.1701183248664.JavaMail.zimbra@univ-eiffel.fr> ----- Original Message ----- > From: "Brian Goetz" > To: "Nolwenn Doucet" > Cc: "amber-dev" > Sent: Monday, November 27, 2023 6:02:01 PM > Subject: Re: Switch expression with enum and when clause > Currently, there are two kinds of cases: constant cases and pattern cases. In > the long term, we would like to make constant cases go away, and turn these > into constant patterns ? at which point the restriction on guards will be > lifted. Also "case null" and "default" can not have a guard too. regards, R?mi > >> On Nov 23, 2023, at 6:11 PM, Nolwenn Doucet wrote: >> >> Hello, >> >> I play with switch expression in java 21 and try to use a when clause on enum >> values to check >> a predicate on a class field and sadly it?s not possible. >> >> Will it be possible to do this in a future release or it?s irrelevant use of >> when clause? >> >> Nolwenn >> >> public class Rental { >> >> private final Movie movie; >> private final int daysRented; >> >> public Rental(Movie movie, int daysRented) { >> this.movie = movie; >> this.daysRented = daysRented; >> } >> >> int renterPoints() { >> return switch(movie.type()) { >> case MovieType.NEW_RELEASE when daysRented > 1 -> 2; >> case MovieType.NEW_RELEASE, MovieType.CHILDRENS, MovieType.REGULAR -> 1; >> }; >> } >> } >> >> public record Movie(String title, MovieType type) {} >> >> public enum MovieType { >> CHILDRENS, NEW_RELEASE, REGULAR; >> } >> >> javac Rental.java >> Rental.java:22: error: : or -> expected >> case MovieType.NEW_RELEASE when daysRented > 1 -> 2; >> ^ >> Rental.java:22: error: not a statement >> case MovieType.NEW_RELEASE when daysRented > 1 -> 2; >> ^ >> Rental.java:22: error: ';' expected > > case MovieType.NEW_RELEASE when daysRented > 1 -> 2; From leonid.arbouzov at oracle.com Tue Nov 28 18:08:52 2023 From: leonid.arbouzov at oracle.com (Leonid Arbuzov) Date: Tue, 28 Nov 2023 10:08:52 -0800 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> References: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> Message-ID: <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> Hi Ron, JLS 12.1 states that "The Java Virtual Machine starts execution by invoking the *method main* of some*specified class or interface*..." You are right that Java SE doesn't say how exactly JVM is launched. The JCK handles this by requesting an user to provide a command that start his tested JVM. The command can be as script, a wrapper code, etc. But it should be able to take a test main class name as an argument. There are other ways to start JVM (for example, manually) but still the JCK should be able to feed it with test main class name. Also JCK compiler tests are run in two steps: - a first step: to? run *tested *Java compiler that compile test sources and generate classes - a second step: to run *reference *JVM to execute the generated classes - this is to verify that tested compiler generate proper classes. To summarize: the JCK should be able to find out a test class name to be able to run it. If the JCK doesn't know classes generated then it can skip the second step. But obviously this would make JCK tests much weaker. Thanks, Leonid JCK Team On 11/28/2023 4:22 AM, Ron Pressler wrote: > >> On 27 Nov 2023, at 20:25, Leonid Arbuzov wrote: >> >> >> How the JCK can launch a test class not knowing its name in an implementation-independent manner? >> > Is launching *any* Java program specified SE even if you do know the name of its main class? > > For example, JLS ?12.1.4 specifies the `main` method but doesn?t specify how the main class is launched. Does it matter, then, that the chosen name for the main class is implementation-specific given that launching the main class is also implementation-specific? > > Perhaps the best way to test implicit classes, then, is from *within* the implicit class itself. Like any other main class, it is launched by some implementation-specific mechanism, but once you?re in it, everything is known. You can then get the chosen class name with `this.getClass()?`. > > ? Ron -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Tue Nov 28 18:30:59 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 28 Nov 2023 18:30:59 +0000 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> References: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> Message-ID: > On 28 Nov 2023, at 18:08, Leonid Arbuzov wrote: > > The JCK handles this by requesting an user to provide a command that start his tested JVM. > The command can be as script, a wrapper code, etc. > But it should be able to take a test main class name as an argument. > There are other ways to start JVM (for example, manually) but still the JCK should be able > to feed it with test main class name. I see, so I think the most complete way to do this is have a mechanism to offer the implementation a source file for compilation *and* have the implementation say what class file it generated for top level classes in the file (there will be just one in the case of a ?simple compilation unit?, i.e. a source file containing an implicit class). Alternatively, the JCK could rely on the following from the new spec (although I don?t know to what extent that?s allowed): "In simple implementations of the Java SE Platform, where compilation units are stored in files, the name of this implicitly declared class would typically be the name of the file containing the simple compilation unit minus any extension? So if you can rely on the implementation being file-based (or at least rely on that by default), then you are allowed to infer the name of the class from the name of the source file. At least for such implementation you don?t need to have the implementation tell you what it named the top-level class. ? Ron From leonid.arbouzov at oracle.com Tue Nov 28 18:59:50 2023 From: leonid.arbouzov at oracle.com (Leonid Arbuzov) Date: Tue, 28 Nov 2023 10:59:50 -0800 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: References: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> Message-ID: <16bc4d77-c4f0-4bb0-b084-e444f5561697@oracle.com> > Alternatively, the JCK could rely on the following from the new spec (although I don?t know to what extent that?s allowed): Yes, the JCK can use that typically generated class names. This might work for the most Java SE implementations. Original question was what should the JCK do for those *non-typical* implementations? The JCK can ask an user to provide a custom converter (source name to class name). But this would not work for implementations that generate class names indeterministically. Hopefully there will be none or a few of such ones and the JCK can run a weaker tests for them. But a concern was that JCK users would be allowed to choose to run those weaker tests... Can the spec somehow close this option? Or the JCK can close it on its own? Thanks, -leonid On 11/28/2023 10:30 AM, Ron Pressler wrote: > >> On 28 Nov 2023, at 18:08, Leonid Arbuzov wrote: >> >> The JCK handles this by requesting an user to provide a command that start his tested JVM. >> The command can be as script, a wrapper code, etc. >> But it should be able to take a test main class name as an argument. >> There are other ways to start JVM (for example, manually) but still the JCK should be able >> to feed it with test main class name. > I see, so I think the most complete way to do this is have a mechanism to offer the implementation a source file for compilation *and* have the implementation say what class file it generated for top level classes in the file (there will be just one in the case of a ?simple compilation unit?, i.e. a source file containing an implicit class). > > Alternatively, the JCK could rely on the following from the new spec (although I don?t know to what extent that?s allowed): > > "In simple implementations of the Java SE Platform, where compilation units are stored in files, the name of this implicitly declared class would typically be the name of the file containing the simple compilation unit minus any extension? > > So if you can rely on the implementation being file-based (or at least rely on that by default), then you are allowed to infer the name of the class from the name of the source file. At least for such implementation you don?t need to have the implementation tell you what it named the top-level class. > > ? Ron -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Tue Nov 28 19:05:38 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Tue, 28 Nov 2023 19:05:38 +0000 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: <16bc4d77-c4f0-4bb0-b084-e444f5561697@oracle.com> References: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> <16bc4d77-c4f0-4bb0-b084-e444f5561697@oracle.com> Message-ID: <7B7C6CE3-0CD6-49EF-8969-09252FF431A5@oracle.com> > On 28 Nov 2023, at 18:59, Leonid Arbuzov wrote: > > > Alternatively, the JCK could rely on the following from the new spec (although I don?t know to what extent that?s allowed): > Yes, the JCK can use that typically generated class names. This might work for the most Java SE implementations. Original question was what should the JCK do for those non-typical implementations? The JCK can ask an user to provide a custom converter (source name to class name). > But this would not work for implementations that generate class names indeterministically. Hopefully there will be none or a few of such ones and the JCK can run a weaker tests for them. But a concern was that JCK users would be allowed to choose to run those weaker tests... > Can the spec somehow close this option? Or the JCK can close it on its own? I think the most complete solution is for the JCK in such a case is to require the implementation to provide some script that compiles the source file and returns the class name of the top-level class that could then be used for launching OR a script that compiles and then immediately runs the file. ? Ron From leonid.arbouzov at oracle.com Tue Nov 28 19:44:08 2023 From: leonid.arbouzov at oracle.com (Leonid Arbuzov) Date: Tue, 28 Nov 2023 11:44:08 -0800 Subject: JEP 463: Implicitly Declared Classes (Second Preview) - Draft Spec Clarification In-Reply-To: <7B7C6CE3-0CD6-49EF-8969-09252FF431A5@oracle.com> References: <4A8FF91C-0074-443E-9D80-7E9B7948B725@oracle.com> <53979e37-7a03-48b5-9155-e6a9c99f86ac@oracle.com> <16bc4d77-c4f0-4bb0-b084-e444f5561697@oracle.com> <7B7C6CE3-0CD6-49EF-8969-09252FF431A5@oracle.com> Message-ID: <65d72c76-dc18-48eb-a59c-f07718129e58@oracle.com> Hi Ron, > I think the most complete solution is for the JCK in such a case is to require the implementation to provide some script that compiles the source file and returns the class name of the top-level class that could then be used for launching Great idea. The approach might work. Let us think more in that direction. > ...OR a script that compiles and then immediately runs the file. The JCK runs compiled classfile with a reference JVM not with a tested JVM. Not a problem: the JCK handles those steps. Thanks, -leonid On 11/28/2023 11:05 AM, Ron Pressler wrote: > >> On 28 Nov 2023, at 18:59, Leonid Arbuzov wrote: >> >>> Alternatively, the JCK could rely on the following from the new spec (although I don?t know to what extent that?s allowed): >> Yes, the JCK can use that typically generated class names. This might work for the most Java SE implementations. Original question was what should the JCK do for those non-typical implementations? The JCK can ask an user to provide a custom converter (source name to class name). >> But this would not work for implementations that generate class names indeterministically. Hopefully there will be none or a few of such ones and the JCK can run a weaker tests for them. But a concern was that JCK users would be allowed to choose to run those weaker tests... >> Can the spec somehow close this option? Or the JCK can close it on its own? > I think the most complete solution is for the JCK in such a case is to require the implementation to provide some script that compiles the source file and returns the class name of the top-level class that could then be used for launching OR a script that compiles and then immediately runs the file. > > ? Ron -------------- next part -------------- An HTML attachment was scrubbed... URL: From johannes.spangenberg at hotmail.de Thu Nov 30 00:22:56 2023 From: johannes.spangenberg at hotmail.de (Johannes Spangenberg) Date: Thu, 30 Nov 2023 01:22:56 +0100 Subject: Trailing Commas Message-ID: Hello, I was curious about the potential consideration for extending support for trailing commas. While I don't consider them critical,?I find myself regularly bothered that I cannot use them. I see several areas in the language where they could be beneficial: * Argument list in method calls * Parameter list in method declaration * Throws clause in method declaration * Implements clause in classes * Extends clause in interfaces * Type arguments * Type parameters It's worth noting that array initializers and enum definitions already support trailing commas. There have been instances where I considered replacing a List or Set with an array simply because arrays support trailing commas, whereas List.of does not. A quick google search?brought up JDK-6407472 , but?it's rather dated, and I wouldn't entirely agree with the comment.?Based on my subjective experience, many, if not most, modern languages embrace trailing commas. For instance, the official style guide of Rust and various style guides for JavaScript recommend their use. While Python's official style guide suggests the use of trailing commas, it doesn't make a clear recommendation. Best Regards, Johannes -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Thu Nov 30 19:02:42 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Thu, 30 Nov 2023 19:02:42 +0000 Subject: Trailing Commas In-Reply-To: References: Message-ID: > On 30 Nov 2023, at 00:22, Johannes Spangenberg wrote: > > Hello, I was curious about the potential consideration for extending support for trailing commas. While I don't consider them critical, I find myself regularly bothered that I cannot use them. Hi. Perhaps someone on the language team has already given the technical merits of this matter some thought, but here?s my non-technical argument against making such a change: For every person who has a strong preference in favour of allowing trailing commas where they?re not allowed today you?ll find another with an equally strong preference against allowing them. Additionally, if this option exists, people will want to write or update style guides preferring one style or the other. So the result is a lot of time, and possibly completely disproportionate emotion, spent for what, at best, is little gain. To me this sounds like the kind of change that is bound to require more effort ? not on the implementation perhaps, but in debate ? than it?s worth. ? Ron From brian.goetz at oracle.com Thu Nov 30 22:10:04 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 30 Nov 2023 17:10:04 -0500 Subject: Trailing Commas In-Reply-To: References: Message-ID: The bug evaluation raised two aspects of this: ?- every change we made that "makes life easier for code generators" makes life harder for parsers, and it is not clear that privileging one over the other is a good idea; ?- trailing comma support is intrinsically a bad idea, it is something we sometimes hold our nose and tolerate, but should never like. To these I will add: ?- Trailing comma support in array initializers are almost surely a "because C does it" (everything about array initializers was copied too-literally from C); this was merely a bad reason in 1995, it is a terrible reason today ?- Array initializer context is "special" (compared to, say, method argument lists) because arrays being initialized do not necessarily have static arities, whereas method argument list definitely do.? So even if we tolerate it for array initializers, there is even less reason to tolerate it in more highly structured contexts. On 11/30/2023 2:02 PM, Ron Pressler wrote: > >> On 30 Nov 2023, at 00:22, Johannes Spangenberg wrote: >> >> Hello, I was curious about the potential consideration for extending support for trailing commas. While I don't consider them critical, I find myself regularly bothered that I cannot use them. > Hi. > > Perhaps someone on the language team has already given the technical merits of this matter some thought, but here?s my non-technical argument against making such a change: > > For every person who has a strong preference in favour of allowing trailing commas where they?re not allowed today you?ll find another with an equally strong preference against allowing them. Additionally, if this option exists, people will want to write or update style guides preferring one style or the other. So the result is a lot of time, and possibly completely disproportionate emotion, spent for what, at best, is little gain. To me this sounds like the kind of change that is bound to require more effort ? not on the implementation perhaps, but in debate ? than it?s worth. > > ? Ron > -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Thu Nov 30 22:36:44 2023 From: kevinb at google.com (Kevin Bourrillion) Date: Thu, 30 Nov 2023 14:36:44 -0800 Subject: Trailing Commas In-Reply-To: References: Message-ID: On Thu, Nov 30, 2023 at 2:10?PM Brian Goetz wrote: - trailing comma support is intrinsically a bad idea, it is something we > sometimes hold our nose and tolerate, but should never like. > Huh? I don't know what this means. I don't really expect this feature to happen, but I feel like this thread ought to include some mention of the actual benefits of the feature? Of course it makes some maintenance tasks (i.e. reordering lists) strictly easier. But I don't always see it mentioned that it also leads to smaller diffs, which makes "blame" info slightly more accurate, merge conflicts slightly less common, and code reviews slightly more efficient. Of course, "slightly" is charitable; it's a very small effect. Still, in my non-Java "fun" projects I use them all the time and it seems strictly worse not to. -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Nov 30 23:44:20 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 30 Nov 2023 17:44:20 -0600 Subject: Trailing Commas In-Reply-To: References: Message-ID: On Thu, Nov 30, 2023 at 5:17?PM Kevin Bourrillion wrote: > Of course it makes some maintenance tasks (i.e. reordering lists) strictly > easier. But I don't always see it mentioned that it also leads to smaller > diffs, which makes "blame" info slightly more accurate, merge conflicts > slightly less common, and code reviews slightly more efficient. Of course, > "slightly" is charitable; it's a very small effect. Still, in my non-Java > "fun" projects I use them all the time and it seems strictly worse not to. > My $0.03 (inflation)... Your point about smaller diffs and reordering lists is correct, and (I'm guessing) what originally motivated this feature. However, that motivation only applies when the items you are listing are normally or typically placed on separate lines. That's true e.g. for enum constants, but not for the other stuff like method parameters, etc. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: