From ccherlin at gmail.com Tue May 7 20:58:19 2024 From: ccherlin at gmail.com (Clement Cherlin) Date: Tue, 7 May 2024 15:58:19 -0500 Subject: Exception handling in switch (Preview) In-Reply-To: <2C4027C7-B85E-4BD9-ACD4-512E576E6215@oracle.com> References: <577E666C-5A6F-45B9-8782-50D4CEEE563B@oracle.com> <2C4027C7-B85E-4BD9-ACD4-512E576E6215@oracle.com> Message-ID: On Wed, Apr 24, 2024 at 10:08?PM Guy Steele wrote: On Apr 24, 2024, at 10:50?PM, Kevin Bourrillion wrote: Hey Angelos! For whatever my take is worth here, I'm also skeptical. I think the bar for adding another way to catch exceptions should be really high, and the benefits here wouldn't clear it. I just don't expect the nested switch-in-try will be painful enough *often* enough. This feature would only be applicable when the whole possibly-exception-producing code can fit into a single expression in the switch header . . . This raises a very good question: what do we expect the "whole > possibly-exception-producing code? to look like in practice? > > I conjecture that the attractive situation for using switch-with-?case > throws"-clauses will NOT involve arbitrarily large expressions that might > need to be refactored, but rather a single method call (or possibly an > expression with a single operator) where all argument expressions are > variables or constants, rather than other stuff that might cause exceptions. > > But I am not sure. So maybe this is a conjecture that could be researched. > > ?Guy > > I expect a major consumer of this feature to be streams and other functional constructs. Try-catch is an exclusively block-oriented mechanism. There is as of now no way to catch an exception inside an expression, which is why I think this feature is valuable. Handling exceptions inside a switch expression lambda would be a significant enhancement. getStream().map(value -> switch(someFunction(value)) { case FirstPossibleType fpt -> ... case SecondPossibleType spt -> ... case catch IOException io -> ... case catch IllegalArgumentException ia -> ... }).filter(...) .forEach(...); is an awful lot shorter, cleaner, and easier to read and write than getStream().map(value -> { final SuperType st; try { st = someFunction(value)); } catch (IOException io) { ... } catch (IllegalArgumentException ia) { ... } return switch (st) { case FirstPossibleType fpt -> ... case SecondPossibleType spt -> ... }).filter(...) .forEach(...); Especially given the care that needs to be taken to only catch exceptions thrown by someFunction() and not the switch arms. Side note: I agree that "case catch Exception ex" is far more consistent with the current "catch (Exception ex)" syntax than "case throws Exception ex" is. The practical familiarity, usability and consistency of "case catch" trumps any theoretical virtues of "case throws", especially since grammatical English would demand "case threw Exception ex". Cheers, Clement Cherlin -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Wed May 8 15:49:06 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Wed, 8 May 2024 15:49:06 +0000 Subject: Draft Spec for Third Preview of Implicitly Declared Classes and Instance Main Methods (JEP 477) In-Reply-To: <20240507175517.B3CA16CA058@eggemoggin.niobe.net> References: <20240507175517.B3CA16CA058@eggemoggin.niobe.net> Message-ID: <552F37DA-F69D-4AC3-BF6F-6E973165B822@oracle.com> Dear experts: The first draft of a spec covering JEP 477 (Implicitly Declared Classes and Instance Main Methods (Third Preview)) is available at: https://cr.openjdk.org/~gbierman/jep477/latest/ Feel free to contact me directly or on this list with any comments/corrections. Thanks, Gavin On 7 May 2024, at 18:55, Mark Reinhold wrote: https://openjdk.org/jeps/477 Summary: Evolve the Java programming language so that beginners can write their first programs without needing to understand language features designed for large programs. Far from using a separate dialect of the language, beginners can write streamlined declarations for single-class programs and then seamlessly expand their programs to use more advanced features as their skills grow. Experienced developers can likewise enjoy writing small programs succinctly, without the need for constructs intended for programming in the large. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Tue May 14 22:13:45 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Tue, 14 May 2024 22:13:45 +0000 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) Message-ID: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> Dear experts: The first draft of a spec covering JEP 482 (Flexible Constructor Bodies (Second Preview)) is available at: https://cr.openjdk.org/~gbierman/jep482/latest/ Feel free to contact me directly or on this list with any comments/corrections. Thanks, Gavin On 14 May 2024, at 20:04, Mark Reinhold wrote: https://openjdk.org/jeps/482 Summary: In constructors in the Java programming language, allow statements to appear before an explicit constructor invocation, i.e., super(..) or this(..). The statements cannot reference the instance under construction, but they can initialize its fields. Initializing fields before invoking another constructor makes a class more reliable when methods are overridden. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephan.herrmann at berlin.de Sat May 18 13:33:34 2024 From: stephan.herrmann at berlin.de (Stephan Herrmann) Date: Sat, 18 May 2024 15:33:34 +0200 Subject: Draft Spec for Preview of Module Import Declarations (JEP 476) In-Reply-To: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> References: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> Message-ID: <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> Hi Gavin, I'm having difficulties interpreting this example: import module M; module M { ... uses C; ... } Literal interpretation would suggest that this imports "all the public top level classes and interfaces in the following packages: * The packages exported by the module M to module M. ..." The notion of exporting to self does not seem to be defined, is it? JLS 7 says: "A module categorizes some or all of its packages as exported, which means their classes and interfaces may be accessed from code outside the module." i.e., export regulates accessibility across a module boundary, but in the above example there is no such boundary. Should the module import still be limited to exported packages? But then: exported to whom? Would a qualified export to some other module M2 hide that package from the module M itself (wrt the module import)? At least the requirement that M is read by M is satisfied, according to a comment in JLS 7.3. thanks, Stephan Am 26.04.24 um 12:07 schrieb Gavin Bierman: > Dear experts: > > The first draft of a spec covering JEP 476 (Module Import Declarations (Preview)) > > https://cr.openjdk.org/~gbierman/jep476/latest/ > > > Feel free to contact me directly or on this list with any comments. > > Thanks > Gavin > >> On 17 Apr 2024, at 19:58, Mark Reinhold wrote: >> >> https://openjdk.org/jeps/476 >> >> ?Summary: Enhance the Java programming language with the ability to >> ?succinctly import all of the packages exported by a module. This >> ?simplifies the reuse of modular libraries, but does not require the >> ?importing code to be in a module itself. This is a preview language >> ?feature. >> >> - Mark From gavin.bierman at oracle.com Fri May 24 13:36:08 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Fri, 24 May 2024 13:36:08 +0000 Subject: Draft Spec for Preview of Module Import Declarations (JEP 476) In-Reply-To: <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> References: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> Message-ID: <8E5B105E-FE43-4717-B4EC-F05E2D6DFA8D@oracle.com> Hi Stephan, Thanks for your email. Yes, example 7.5.5-2 is missing information to make it more intelligible; sorry about that. But you are on the right track - we can use the simple name C in the uses directive *if it has been exported to M*. As you spotted, the JLS requires that the "read by" relation is reflexive, so that?s how a module exports to itself. More concretely, consider this slight expansion of the example: import module M; module M { exports p1 to M1; exports p2; exports p3 to M; uses C; } The effect of the import module M declaration is to bring in: 1. Package p2, because it's exported by M to all comers, including M; and 2. Package p3, because it's exported in a qualified fashion to M. And, to answer your question, it does NOT bring in package p1 as that is only exported to M1. In other words (and finally filling in all the details!): //A.java package p1; class A {} //B.java package p2; class B {} //C.java package p3; class C {} //module-info.java import module M; module M { exports p1 to M1; exports p2; exports p3 to M; uses A; // error uses B; // ok uses C; // ok } Hope this helps, and thanks once again. I?ll clarify the spec. Gavin On 18 May 2024, at 14:33, Stephan Herrmann wrote: Hi Gavin, I'm having difficulties interpreting this example: import module M; module M { ... uses C; ... } Literal interpretation would suggest that this imports "all the public top level classes and interfaces in the following packages: * The packages exported by the module M to module M. ..." The notion of exporting to self does not seem to be defined, is it? JLS 7 says: "A module categorizes some or all of its packages as exported, which means their classes and interfaces may be accessed from code outside the module." i.e., export regulates accessibility across a module boundary, but in the above example there is no such boundary. Should the module import still be limited to exported packages? But then: exported to whom? Would a qualified export to some other module M2 hide that package from the module M itself (wrt the module import)? At least the requirement that M is read by M is satisfied, according to a comment in JLS 7.3. thanks, Stephan Am 26.04.24 um 12:07 schrieb Gavin Bierman: Dear experts: The first draft of a spec covering JEP 476 (Module Import Declarations (Preview)) https://cr.openjdk.org/~gbierman/jep476/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin On 17 Apr 2024, at 19:58, Mark Reinhold wrote: https://openjdk.org/jeps/476 Summary: Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephan.herrmann at berlin.de Sat May 25 15:12:07 2024 From: stephan.herrmann at berlin.de (Stephan Herrmann) Date: Sat, 25 May 2024 17:12:07 +0200 Subject: Draft Spec for Preview of Module Import Declarations (JEP 476) In-Reply-To: <8E5B105E-FE43-4717-B4EC-F05E2D6DFA8D@oracle.com> References: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> <8E5B105E-FE43-4717-B4EC-F05E2D6DFA8D@oracle.com> Message-ID: <86d97097-28d2-4008-bb59-4129e44a2884@berlin.de> Hi Gavin, Thanks for clarifications. When I had first looked at the spec example I briefly wondered: why should an export be needed to import stuff from the current module, perhaps the intention was to focus on accessibility, not exports? Looking at your answer my reaction now was: sure why should module-info mention types that are not exported? Then I recalled that service implementations need not (should not?) be exported. So that's probably where exports-to-self could come in to play, if indeed you want to use module import to refer to service implementations (not much to be gained here, though). Next I tried this with javac 23-ea build 24, with these results: - module import in module-info doesn't seem to be evaluated yet - importing the current module (anywhere) gives "module mtest does not read: mtest" :) Still, from a specification point of view all looks clear to me now. Based on 'reads' being reflexive there's no strict need for special case rules indeed. thanks, Stephan Am 24.05.24 um 15:36 schrieb Gavin Bierman: > Hi Stephan, > > Thanks for your email. Yes, example 7.5.5-2 is missing information to make it > more intelligible; sorry about that. > > But you are on the right track - we can use the simple name C in the uses > directive *if it has been exported to M*. As you spotted, the JLS requires that > the "read by" relation is reflexive, so that?s how a module exports to itself. > > More concretely, consider this slight expansion of the example: > > importmodule M; > module M { > exports p1 to M1; > exports p2; > exports p3 to M; > usesC; > } > > The effect of the import module M declaration is to bring in: > > 1. Package p2,?because it's exported by M to all comers, including M; and > 2. Package p3, because it's exported in a qualified fashion to M. > > And, to answer your question, it does NOT bring in package p1 as that is only > exported to M1. In other words (and finally filling in all the details!): > > //A.java > package p1; > class A {} > > //B.java > package p2; > class B {} > > //C.java > package p3; > class C {} > > > //module-info.java > import module M; > module M { > exports p1 to M1; > exports p2; > exports p3 to M; > uses A; // error > uses B; // ok > uses C; // ok > } > > Hope this helps, and thanks once again. I?ll clarify the spec. > > Gavin > >> On 18 May 2024, at 14:33, Stephan Herrmann wrote: >> >> Hi Gavin, >> >> I'm having difficulties interpreting this example: >> >> import module M; >> module M { >> ???... >> ???uses C; >> ???... >> } >> >> Literal interpretation would suggest that this imports >> "all the public top level classes and interfaces in the following packages: >> * The packages exported by the module M to module M. ..." >> >> The notion of exporting to self does not seem to be defined, is it? >> JLS 7 says: "A module categorizes some or all of its packages as exported, >> which means their classes and interfaces may be accessed from code outside the >> module." i.e., export regulates accessibility across a module boundary, but in >> the above example there is no such boundary. >> >> Should the module import still be limited to exported packages? But then: >> exported to whom? Would a qualified export to some other module M2 hide that >> package from the module M itself (wrt the module import)? >> >> At least the requirement that M is read by M is satisfied, according to a >> comment in JLS 7.3. >> >> thanks, >> Stephan >> >> >> Am 26.04.24 um 12:07 schrieb Gavin Bierman: >>> Dear experts: >>> The first draft of a spec covering JEP 476 (Module Import Declarations (Preview)) >>> https://cr.openjdk.org/~gbierman/jep476/latest/ >>> >>> Feel free to contact me directly or on this list with any comments. >>> Thanks >>> Gavin >>>> On 17 Apr 2024, at 19:58, Mark Reinhold wrote: >>>> >>>> https://openjdk.org/jeps/476 >>>> >>>> ?Summary: Enhance the Java programming language with the ability to >>>> ?succinctly import all of the packages exported by a module. This >>>> ?simplifies the reuse of modular libraries, but does not require the >>>> ?importing code to be in a module itself. This is a preview language >>>> ?feature. >>>> >>>> - Mark >> > From gavin.bierman at oracle.com Mon May 27 22:31:34 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Mon, 27 May 2024 22:31:34 +0000 Subject: Draft Spec for Preview of Module Import Declarations (JEP 476) In-Reply-To: <86d97097-28d2-4008-bb59-4129e44a2884@berlin.de> References: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> <8E5B105E-FE43-4717-B4EC-F05E2D6DFA8D@oracle.com> <86d97097-28d2-4008-bb59-4129e44a2884@berlin.de> Message-ID: Thanks Stephan. Indeed; that bug got fixed reasonably recently https://bugs.openjdk.org/browse/JDK-8332890 :-) Gavin On 25 May 2024, at 16:12, Stephan Herrmann wrote: Hi Gavin, Thanks for clarifications. When I had first looked at the spec example I briefly wondered: why should an export be needed to import stuff from the current module, perhaps the intention was to focus on accessibility, not exports? Looking at your answer my reaction now was: sure why should module-info mention types that are not exported? Then I recalled that service implementations need not (should not?) be exported. So that's probably where exports-to-self could come in to play, if indeed you want to use module import to refer to service implementations (not much to be gained here, though). Next I tried this with javac 23-ea build 24, with these results: - module import in module-info doesn't seem to be evaluated yet - importing the current module (anywhere) gives "module mtest does not read: mtest" :) Still, from a specification point of view all looks clear to me now. Based on 'reads' being reflexive there's no strict need for special case rules indeed. thanks, Stephan Am 24.05.24 um 15:36 schrieb Gavin Bierman: Hi Stephan, Thanks for your email. Yes, example 7.5.5-2 is missing information to make it more intelligible; sorry about that. But you are on the right track - we can use the simple name C in the uses directive *if it has been exported to M*. As you spotted, the JLS requires that the "read by" relation is reflexive, so that?s how a module exports to itself. More concretely, consider this slight expansion of the example: importmodule M; module M { exports p1 to M1; exports p2; exports p3 to M; usesC; } The effect of the import module M declaration is to bring in: 1. Package p2, because it's exported by M to all comers, including M; and 2. Package p3, because it's exported in a qualified fashion to M. And, to answer your question, it does NOT bring in package p1 as that is only exported to M1. In other words (and finally filling in all the details!): //A.java package p1; class A {} //B.java package p2; class B {} //C.java package p3; class C {} //module-info.java import module M; module M { exports p1 to M1; exports p2; exports p3 to M; uses A; // error uses B; // ok uses C; // ok } Hope this helps, and thanks once again. I?ll clarify the spec. Gavin On 18 May 2024, at 14:33, Stephan Herrmann wrote: Hi Gavin, I'm having difficulties interpreting this example: import module M; module M { ... uses C; ... } Literal interpretation would suggest that this imports "all the public top level classes and interfaces in the following packages: * The packages exported by the module M to module M. ..." The notion of exporting to self does not seem to be defined, is it? JLS 7 says: "A module categorizes some or all of its packages as exported, which means their classes and interfaces may be accessed from code outside the module." i.e., export regulates accessibility across a module boundary, but in the above example there is no such boundary. Should the module import still be limited to exported packages? But then: exported to whom? Would a qualified export to some other module M2 hide that package from the module M itself (wrt the module import)? At least the requirement that M is read by M is satisfied, according to a comment in JLS 7.3. thanks, Stephan Am 26.04.24 um 12:07 schrieb Gavin Bierman: Dear experts: The first draft of a spec covering JEP 476 (Module Import Declarations (Preview)) https://cr.openjdk.org/~gbierman/jep476/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin On 17 Apr 2024, at 19:58, Mark Reinhold wrote: https://openjdk.org/jeps/476 Summary: Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Mon May 27 22:31:34 2024 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Mon, 27 May 2024 22:31:34 +0000 Subject: Draft Spec for Preview of Module Import Declarations (JEP 476) In-Reply-To: <86d97097-28d2-4008-bb59-4129e44a2884@berlin.de> References: <30E93260-DC44-4E4E-977B-41C9348FDE62@oracle.com> <978ce036-8d4f-4ce3-bdc9-379dd091a04a@berlin.de> <8E5B105E-FE43-4717-B4EC-F05E2D6DFA8D@oracle.com> <86d97097-28d2-4008-bb59-4129e44a2884@berlin.de> Message-ID: Thanks Stephan. Indeed; that bug got fixed reasonably recently https://bugs.openjdk.org/browse/JDK-8332890 :-) Gavin On 25 May 2024, at 16:12, Stephan Herrmann wrote: Hi Gavin, Thanks for clarifications. When I had first looked at the spec example I briefly wondered: why should an export be needed to import stuff from the current module, perhaps the intention was to focus on accessibility, not exports? Looking at your answer my reaction now was: sure why should module-info mention types that are not exported? Then I recalled that service implementations need not (should not?) be exported. So that's probably where exports-to-self could come in to play, if indeed you want to use module import to refer to service implementations (not much to be gained here, though). Next I tried this with javac 23-ea build 24, with these results: - module import in module-info doesn't seem to be evaluated yet - importing the current module (anywhere) gives "module mtest does not read: mtest" :) Still, from a specification point of view all looks clear to me now. Based on 'reads' being reflexive there's no strict need for special case rules indeed. thanks, Stephan Am 24.05.24 um 15:36 schrieb Gavin Bierman: Hi Stephan, Thanks for your email. Yes, example 7.5.5-2 is missing information to make it more intelligible; sorry about that. But you are on the right track - we can use the simple name C in the uses directive *if it has been exported to M*. As you spotted, the JLS requires that the "read by" relation is reflexive, so that?s how a module exports to itself. More concretely, consider this slight expansion of the example: importmodule M; module M { exports p1 to M1; exports p2; exports p3 to M; usesC; } The effect of the import module M declaration is to bring in: 1. Package p2, because it's exported by M to all comers, including M; and 2. Package p3, because it's exported in a qualified fashion to M. And, to answer your question, it does NOT bring in package p1 as that is only exported to M1. In other words (and finally filling in all the details!): //A.java package p1; class A {} //B.java package p2; class B {} //C.java package p3; class C {} //module-info.java import module M; module M { exports p1 to M1; exports p2; exports p3 to M; uses A; // error uses B; // ok uses C; // ok } Hope this helps, and thanks once again. I?ll clarify the spec. Gavin On 18 May 2024, at 14:33, Stephan Herrmann wrote: Hi Gavin, I'm having difficulties interpreting this example: import module M; module M { ... uses C; ... } Literal interpretation would suggest that this imports "all the public top level classes and interfaces in the following packages: * The packages exported by the module M to module M. ..." The notion of exporting to self does not seem to be defined, is it? JLS 7 says: "A module categorizes some or all of its packages as exported, which means their classes and interfaces may be accessed from code outside the module." i.e., export regulates accessibility across a module boundary, but in the above example there is no such boundary. Should the module import still be limited to exported packages? But then: exported to whom? Would a qualified export to some other module M2 hide that package from the module M itself (wrt the module import)? At least the requirement that M is read by M is satisfied, according to a comment in JLS 7.3. thanks, Stephan Am 26.04.24 um 12:07 schrieb Gavin Bierman: Dear experts: The first draft of a spec covering JEP 476 (Module Import Declarations (Preview)) https://cr.openjdk.org/~gbierman/jep476/latest/ Feel free to contact me directly or on this list with any comments. Thanks Gavin On 17 Apr 2024, at 19:58, Mark Reinhold wrote: https://openjdk.org/jeps/476 Summary: Enhance the Java programming language with the ability to succinctly import all of the packages exported by a module. This simplifies the reuse of modular libraries, but does not require the importing code to be in a module itself. This is a preview language feature. - Mark -------------- next part -------------- An HTML attachment was scrubbed... URL: From stephan.herrmann at berlin.de Tue May 28 17:20:00 2024 From: stephan.herrmann at berlin.de (Stephan Herrmann) Date: Tue, 28 May 2024 19:20:00 +0200 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> Message-ID: <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> Hi Gavin, One remark, one question: In ?8.8.7.1 it says: "References to instance variables of class C are disallowed ..." which seems to disqualify the following code: public class C { String name; Test(C other) { System.out.println(other.name); super(); } } I assume this paragraph in italics is not normative, right? Later paragraphs are clear that this applies to single name references and this references, but still the above sentence seems misleading. The same applies for the next two sentences (regarding other.foo(), or new other.Inner()). Now for the question: two sentences from the previous edition have been removed, but they seem to be needed, still: * ?8.1.3: "An instance of an anonymous class whose declaration occurs in a pre-construction context (8.8.7.1) has no immediately enclosing instance." * ?15.9.2: "If C is an anonymous class, then: o If the class instance creation expression occurs in a static context or a pre-construction context, then i has no immediately enclosing instance. Mention of "pre-construction context" removed. Has this been moved to some other place, is it covered by some other rule (which?), or was removal of those parts from ?8.1.3 and ?15.9.2 unintentional after all? thanks Stephan Am 15.05.24 um 00:13 schrieb Gavin Bierman: > Dear experts: > > The first draft of a spec covering JEP 482 (Flexible Constructor Bodies (Second > Preview)) is available at: > > https://cr.openjdk.org/~gbierman/jep482/latest/ > > > Feel free to contact me directly or on this list with any comments/corrections. > > Thanks, > Gavin > >> On 14 May 2024, at 20:04, Mark Reinhold wrote: >> >> https://openjdk.org/jeps/482 >> >> ?Summary: In constructors in the Java programming language, allow >> ?statements to appear before an explicit constructor invocation, i.e., >> ?super(..) or this(..). The statements cannot reference the instance >> ?under construction, but they can initialize its fields. Initializing >> ?fields before invoking another constructor makes a class more reliable >> ?when methods are overridden. This is a preview language feature. >> >> - Mark From maurizio.cimadamore at oracle.com Wed May 29 14:57:13 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Wed, 29 May 2024 15:57:13 +0100 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> Message-ID: On 28/05/2024 18:20, Stephan Herrmann wrote: > * ?8.1.3: "An instance of an anonymous class whose declaration occurs > in a pre-construction context (8.8.7.1) has no immediately enclosing > instance." Late to the party. I?m kind of questioning that rule a little bit, to be honest. More specifically, the text that says that a local/anon class in a static context has no enclosing instance seems to cast too wide of a net. If that?s the case, then we can?t really prove (following the rules in the spec) how references to members in enclosing instances are resolved. Consider the following example: |class Outer { class Inner { Inner() { class Local { void test() { m(); } } new Local().test(); super(); } } void m() { } public static void main(String[] args) { new Outer().new Inner(); } } | Here, |Local| occurs in an early context (used to be pre-constructor, or static). So it has no enclosing instance. But then, how can it refer to |Outer::m| ? In 15.12.1 we say: If there is an enclosing class or interface declaration of which that method is a member, let E be the innermost such class or interface declaration. The type to search is the type of E.this (?15.8.4). Ok, so the above program is valid if |Outer.this| makes sense. But, as per 15.8.4: The value of a qualified this expression TypeName.this is the n?th lexically enclosing instance of this. But there?s no enclosing instance for |Local|, so what does |Outer.this| evaluates to? I think this has always been a bit of an issue - we always treated anonymous classes occurring in super calls as ?static?, but that doesn?t explain how such classes seem to have access to members of enclosing classes. Under the hood, this works, because javac captures the enclosing instance reference of |Inner| and passes that to |Local|. In other words, it?s as if, from a translation perspective, the enclosing instance of |Local| was |Outer|. In fact, if we look at the generated class for |Local| we see this: |class Outer$Inner$1Local { final Outer val$this$0; Outer$Inner$1Local(Outer); void test(); } | Note that there?s no |this$0| field, but |val$this$0| instead. In other words, it?s as if the |this$0| reference in the |Inner| constructor has been captured by the local class. While this works out in practice, it does seem a very roundabout way to say that |Local| indeed has an enclosing instance (|Outer|) - and javac?s backend trickery of course doesn?t even explain why the above program is accepted in the first place. It seems like this area needs a bit of an overhaul? Or am I missing something? Cheers Maurizio ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From daniel.smith at oracle.com Thu May 30 04:39:55 2024 From: daniel.smith at oracle.com (Dan Smith) Date: Thu, 30 May 2024 04:39:55 +0000 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> Message-ID: On May 29, 2024, at 7:57?AM, Maurizio Cimadamore wrote: On 28/05/2024 18:20, Stephan Herrmann wrote: * ?8.1.3: "An instance of an anonymous class whose declaration occurs in a pre-construction context (8.8.7.1) has no immediately enclosing instance." To clarify the model: yes, this rule was intentionally removed. It becomes very complicated if you want to make rules about which enclosing instances exist or don't exist based on positioning within a constructor. Example: class C1 { C1() { super(); class C2 { // not early for C1 C2() { class C3 { // early for C2 C3() { super(); class C4 { // not early for C3 ... } } } super(); } } } } Does C4 have a 1st enclosing instance? Yep. 2nd? Maybe no? 3rd? It better... Instead, the approach we settled on was: early construction contexts have no bearing on whether a class "has" an enclosing instance. It always does, if it's not in a static context. Meanwhile, there are a bunch of rules about what you can reference from an early construction context *of a particular class*. So, e.g., C4 is in the early construction context of C2, so it is illegal to reference the members of C2 in the body of C4. (Note that this model has nothing to do with how a compiler translates these classes into bytecode, which enclosing instances get stored in fields, etc. That's a separate problem for javac to deal with.) Consider the following example: class Outer { class Inner { Inner() { class Local { void test() { m(); } } new Local().test(); super(); } } void m() { } public static void main(String[] args) { new Outer().new Inner(); } } Here, Local occurs in an early context (used to be pre-constructor, or static). So it has no enclosing instance. But then, how can it refer to Outer::m ? Revised rules say that Local does not appear in the early construction context *of Outer*, so therefore is allowed to refer to the members of Outer. In 15.12.1 we say: If there is an enclosing class or interface declaration of which that method is a member, let E be the innermost such class or interface declaration. The type to search is the type of E.this (?15.8.4). Ok, so the above program is valid if Outer.this makes sense. But, as per 15.8.4: The value of a qualified this expression TypeName.this is the n?th lexically enclosing instance of this. But there?s no enclosing instance for Local, so what does Outer.this evaluates to? Yep, that's part of what motivated this change. You need to be able to talk about the full chain of enclosing instances of Local, even if some of them are "unusable". I think this has always been a bit of an issue - we always treated anonymous classes occurring in super calls as ?static?, but that doesn?t explain how such classes seem to have access to members of enclosing classes. Agree, it wasn't well-specified before. It seems like this area needs a bit of an overhaul? Or am I missing something? Right. The first step was to recognize that an early construction context is not the same thing as a static context. The next step was to allow enclosing instances for classes in early construction contexts. And the third step was to ensure that the restrictions on references from early construction contexts continue to apply appropriately inside nested classes. I believe this is now appropriately handled by the spec changes Gavin shared, but it's good to validate that with extra eyeballs. -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu May 30 10:13:15 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 30 May 2024 11:13:15 +0100 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> Message-ID: <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> Thanks Dan, I see the new rules. So basically, a local class in a pre-construction context has an enclosing instance, but then we have a bunch of rules which say that if I do "Type.this", and I'm in the pre-construction context for Type, that's an error. I note that this is effectively equivalent to say that the enclosing instance of the local class is the first enclosing instance that does not appear in a pre-construction context, correct? If we stated that, once and for all (in 8.1.3), couldn't we then avoid the need for having other special rules? (e.g. if class L appears in a pre-construction context for C, and C has enclosing instance D, then, if we say that the enclosing instance of L is D, automatically C.this becomes ill-formed). Was this possibility considered, or would it be too problematic to have an enclosing instance not match the innermost lexically encloisng class? P.S. How common is this stuff? This seems to be working today, with some bits of javac heroics (some bits of which seem to be working mostly by accident). From the perspective of Java developers, wouldn't it be easier to say that every class declared in a pre-construction context is static, period, and cannot reference anyhing from enclosing contexts? I realize this would be an incompatible change, but it seems to me that the status quo leaves developers guessing as to whether some code would compile or not. Maurizio On 30/05/2024 05:39, Dan Smith wrote: >> On May 29, 2024, at 7:57?AM, Maurizio Cimadamore >> wrote: >> >> On 28/05/2024 18:20, Stephan Herrmann wrote: >> >>> * ?8.1.3: "An instance of an anonymous class whose declaration >>> occurs in a pre-construction context (8.8.7.1) has no immediately >>> enclosing instance." >> > > To clarify the model: yes, this rule was intentionally removed. It > becomes very complicated if you want to make rules about which > enclosing instances exist or don't exist based on positioning within a > constructor. Example: > > class C1 { > ? ? C1() { > ? ? ? ? super(); > ? ? ? ? class C2 { // not early for C1 > ? ? ? ? ? ? C2() { > ? ? ? ? ? ? ? ? class C3 { // early for C2 > ? ? ? ? ? ? ? ? ? ? C3() { > ? ? ? ? ? ? ? ? ? ? ? ? super(); > ? ? ? ? ? ? ? ? ? ? ? ? class C4 { // not early for C3 > ? ? ? ? ? ? ? ? ? ? ? ? ? ? ... > ? ? ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? ? ? super(); > ? ? ? ? ? ? } > ? ? ? ? } > ? ? } > } > > Does C4 have a 1st enclosing instance? Yep. 2nd? Maybe no? 3rd? It > better... > > Instead, the approach we settled on was: early construction contexts > have no bearing on whether a class "has" an enclosing instance. It > always does, if it's not in a static context. > > Meanwhile, there are a bunch of rules about what you can reference > from an early construction context *of a particular class*. So, e.g., > C4 is in the early construction context of C2, so it is illegal to > reference the members of C2 in the body of C4. > > (Note that this model has nothing to do with how a compiler translates > these classes into bytecode, which enclosing instances get stored in > fields, etc. That's a separate problem for javac to deal with.) > >> Consider the following example: >> |class Outer { class Inner { Inner() { class Local { void test() { >> m(); } } new Local().test(); super(); } } void m() { } public static >> void main(String[] args) { new Outer().new Inner(); } } | >> >> Here, |Local| occurs in an early context (used to be pre-constructor, >> or static). So it has no enclosing instance. But then, how can it >> refer to |Outer::m| ? >> > Revised rules say that Local does not appear in the early construction > context *of Outer*, so therefore is allowed to refer to the members of > Outer. > >> In 15.12.1 we say: >> >> If there is an enclosing class or interface declaration of which >> that method is a member, let E be the innermost such class or >> interface declaration. The type to search is the type of E.this >> (?15.8.4). >> >> Ok, so the above program is valid if |Outer.this| makes sense. But, >> as per 15.8.4: >> >> The value of a qualified this expression TypeName.this is the >> n?th lexically enclosing instance of this. >> >> But there?s no enclosing instance for |Local|, so what does >> |Outer.this| evaluates to? >> > Yep, that's part of what motivated this change. You need to be able to > talk about the full chain of enclosing instances of Local, even if > some of them are "unusable". > >> I think this has always been a bit of an issue - we always treated >> anonymous classes occurring in super calls as ?static?, but that >> doesn?t explain how such classes seem to have access to members of >> enclosing classes. >> > Agree, it wasn't well-specified before. > >> It seems like this area needs a bit of an overhaul? Or am I missing >> something? >> > Right. The first step was to recognize that an early construction > context is not the same thing as a static context. The next step was > to allow enclosing instances for classes in early construction > contexts. And the third step was to ensure that the restrictions on > references from early construction contexts continue to apply > appropriately inside nested classes. > > I believe this is now appropriately handled by the spec changes Gavin > shared, but it's good to validate that with extra eyeballs. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu May 30 10:14:59 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 30 May 2024 11:14:59 +0100 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> Message-ID: <31ecf4e4-b0f8-46f3-b882-60f21bd9553d@oracle.com> On 30/05/2024 11:13, Maurizio Cimadamore wrote: > I see the new rules Hit send too fast :-) Some of the details you mentioned should really be added to the changelog. I looked at that yesterday briefly and concluded... meh, no relevant changes here - but there are indeed changes in how the feature works, and they should be called out. Maurizio From archie.cobbs at gmail.com Thu May 30 22:16:37 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 30 May 2024 16:16:37 -0600 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> Message-ID: On Thu, May 30, 2024 at 5:08?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > I note that this is effectively equivalent to say that the enclosing > instance of the local class is the first enclosing instance that does not > appear in a pre-construction context, correct? If we stated that, once and > for all (in 8.1.3), couldn't we then avoid the need for having other > special rules? > (When trying to play with the JLS I still feel like a child wielding a weapon that's way too heavy for me) At one point I took a stab at what ?15.9.2 might say if you went down that route. It started with something like this: For any expression or class declaration E, define the first available enclosing instance of E, if any, as follows: o If E occurs in a static context, then there is no first available enclosing instance of E. o If E is a top-level class declaration, a static class declaration, or an interface declaration, then there is no first available enclosing instance of E. o Otherwise, let O be the immediately enclosing class declaration of E. o If E occurs in an early construction context of O, then the first available enclosing instance of E is the first available enclosing instance of O, if any. o Otherwise, the first available enclosing instance of E is O's instance of this. What's new here is that the definition is recursive, which seems to be inescapable if you want the rules to match the compiler's actual behavior. But I agree with Dan that it's simpler to avoid all that and just say when you can and cannot reference the enclosing instances, i.e., remember we only need to specify the language here, not the compilation process. This works for local and anonymous classes because the entire class, and therefore all references to an enclosing instance from the class, are either in a pre-construction context or not, and so there's never a difference between "the enclosing instance X exists" and "the expression X.this is legal". Of course member classes are different - the enclosing instance is provided either explicitly or implicitly at construction time, and separate rules apply to handle that. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu May 30 22:24:45 2024 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 30 May 2024 16:24:45 -0600 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> Message-ID: On Thu, May 30, 2024 at 5:08?AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > How common is this stuff? This seems to be working today, with some bits > of javac heroics (some bits of which seem to be working mostly by > accident). From the perspective of Java developers, wouldn't it be easier > to say that every class declared in a pre-construction context is static, > period, and cannot reference anyhing from enclosing contexts? I realize > this would be an incompatible change, but it seems to me that the status > quo leaves developers guessing as to whether some code would compile or not. > I think doing that would be more surprising. Remember pre-construction context includes superclass constructor parameters, and developers are already commonly referring to 2nd enclosing instances in code looking like this example: class Outer { String getName() { return "fred"; } class Inner extends Thread { Inner() { super(new Runnable() { @Override public void run() { System.out.println("hello from " + Outer.this.getName()); } }); } } } -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu May 30 22:55:28 2024 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 30 May 2024 23:55:28 +0100 Subject: Draft Spec for Second Preview of Flexible Constructor Bodies (JEP 482) In-Reply-To: References: <125ABABF-4D7C-4B57-B5D2-E81C3FC86FB1@oracle.com> <89c6e982-5129-47bf-950d-27b5ebe51eb6@berlin.de> <33ce0900-5b19-4d73-8f66-e94477d28fc9@oracle.com> Message-ID: On 30/05/2024 23:24, Archie Cobbs wrote: > Remember pre-construction context includes superclass constructor > parameters, and developers are already commonly referring to 2nd > enclosing instances in code looking like this example: > > class Outer { > ? ? String getName() { > ? ? ? ? return "fred"; > ? ? } > ? ? class Inner extends Thread { > ? ? ? ? Inner() { > ? ? ? ? ? ? super(new Runnable() { > ? ? ? ? ? ? ? ? @Override > ? ? ? ? ? ? ? ? public void run() { > ? ? ? ? ? ? ? ? ? ? System.out.println("hello from " + > Outer.this.getName()); > ? ? ? ? ? ? ? ? } > ? ? ? ? ? ? }); > ? ? ? ? } > ? ? } > } Sure, I know that super constructor arguments are part of the issue (in fact that's the angle I was looking this problem at before I realized it also impacted JEP 482). That said, I'm not sure how common of a pattern this really is. All the examples I've seen so far have a certain artificial vibe to them. The kind of stuff compiler writers like us might want to write in a test :-) It would be helpful I think to run some analysis and get some numbers. I'll see if I can do that, I think I know where to look. Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: