From redio.development at gmail.com Sun Jan 1 17:47:48 2023 From: redio.development at gmail.com (Red IO) Date: Sun, 1 Jan 2023 18:47:48 +0100 Subject: Function level try recourse directives. In-Reply-To: <20221229170806.4b226b36@sunflower.int.arc7.info> References: <20221227140726.04f72129@sunflower.int.arc7.info> <20221227185317.4acbd1c5@sunflower.int.arc7.info> <20221229102821.0cb20fed@sunflower.int.arc7.info> <20221229170806.4b226b36@sunflower.int.arc7.info> Message-ID: I am curious now on how language features are done in the first place. I could not find any good resources on how to add features to the jdk. I only found a guide on how to build the jdk. Do you know any good resources to help me with this? (I do not ask for someone to explain the process since I am sure it's a lot. I'm sure there should be some documents but I can't find them) Thanks in advance RedIODev On Thu, Dec 29, 2022, 18:08 Mark Raynsford wrote: > On 2022-12-29T08:55:25 -0800 > Nathan Reynolds wrote: > > > I understand. However, CloseableCollection is not part of the JDK. It > is > > in a separate library that is probably brand new. It probably is used > only > > by a handful of projects at this time. > > I'm sorry, I think I missed your point (or got my wires crossed with > the replies here). > > -- > Mark Raynsford | https://www.io7m.com > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sun Jan 1 17:52:22 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 1 Jan 2023 17:52:22 +0000 Subject: Function level try recourse directives. In-Reply-To: References: <20221227140726.04f72129@sunflower.int.arc7.info> <20221227185317.4acbd1c5@sunflower.int.arc7.info> <20221229102821.0cb20fed@sunflower.int.arc7.info> <20221229170806.4b226b36@sunflower.int.arc7.info> Message-ID: Significant improvements to the platform are managed through the JEP process. This includes the language, virtual machine, libraries, and tooling. (However, that doesn?t mean that if you have an idea, the right place to start is a JEP. The right place to start is discussing it on the relevant mailing lists.) On Jan 1, 2023, at 12:47 PM, Red IO > wrote: I am curious now on how language features are done in the first place. I could not find any good resources on how to add features to the jdk. I only found a guide on how to build the jdk. Do you know any good resources to help me with this? (I do not ask for someone to explain the process since I am sure it's a lot. I'm sure there should be some documents but I can't find them) Thanks in advance RedIODev On Thu, Dec 29, 2022, 18:08 Mark Raynsford > wrote: On 2022-12-29T08:55:25 -0800 Nathan Reynolds > wrote: > I understand. However, CloseableCollection is not part of the JDK. It is > in a separate library that is probably brand new. It probably is used only > by a handful of projects at this time. I'm sorry, I think I missed your point (or got my wires crossed with the replies here). -- Mark Raynsford | https://www.io7m.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Sun Jan 1 18:01:01 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Sun, 1 Jan 2023 19:01:01 +0100 (CET) Subject: Function level try recourse directives. In-Reply-To: References: <20221227185317.4acbd1c5@sunflower.int.arc7.info> <20221229102821.0cb20fed@sunflower.int.arc7.info> <20221229170806.4b226b36@sunflower.int.arc7.info> Message-ID: <497128433.74512436.1672596061712.JavaMail.zimbra@u-pem.fr> > From: "Brian Goetz" > To: "Red IO" > Cc: "org openjdk" , "Nathan Reynolds" > , "amber-dev" > Sent: Sunday, January 1, 2023 6:52:22 PM > Subject: Re: Function level try recourse directives. > Significant improvements to the platform are managed through the JEP process. Which is itself specified as a JEP [ https://openjdk.org/jeps/1 | https://openjdk.org/jeps/1 ] This is model on the Python Enhancement Proposal (PEP) [ https://peps.python.org/pep-0001/ | https://peps.python.org/pep-0001/ ] R?mi >> On Jan 1, 2023, at 12:47 PM, Red IO < [ mailto:redio.development at gmail.com | >> redio.development at gmail.com ] > wrote: >> I am curious now on how language features are done in the first place. I could >> not find any good resources on how to add features to the jdk. I only found a >> guide on how to build the jdk. Do you know any good resources to help me with >> this? (I do not ask for someone to explain the process since I am sure it's a >> lot. I'm sure there should be some documents but I can't find them) >> Thanks in advance >> RedIODev >> On Thu, Dec 29, 2022, 18:08 Mark Raynsford < [ mailto:org.openjdk at io7m.com | >> org.openjdk at io7m.com ] > wrote: >>> On 2022-12-29T08:55:25 -0800 >>> Nathan Reynolds < [ mailto:numeralnathan at gmail.com | numeralnathan at gmail.com ] > >>> wrote: >>> > I understand. However, CloseableCollection is not part of the JDK. It is >>> > in a separate library that is probably brand new. It probably is used only >>> > by a handful of projects at this time. >>> I'm sorry, I think I missed your point (or got my wires crossed with >>> the replies here). >>> -- >>> Mark Raynsford | [ >>> https://urldefense.com/v3/__https://www.io7m.com__;!!ACWV5N9M2RV99hQ!LQDxMwywciUow4za1rmr_R3IxbfVp9J244adfyL4REcP9Ddyu7PfusR69NlwQq3kMI7E72HqHVztxlyvnb1tT0L3pkMm$ >>> | >>> https://www.io7m.com ] -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 2 04:55:53 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Sun, 1 Jan 2023 23:55:53 -0500 Subject: I am having trouble understanding the purpose of Unconditional Patterns Message-ID: Hello Amber Dev Team, I was working on some code using Pattern-Matching for instanceof, and then I ran into a surprising warning. Here is the code. public class UnconditionalPatternsPreviewWarning { public record Triple(int a, int b, int c) {} public static void main(String[] args) { System.out.println("Java Version = " + System.getProperty("java.version")); final Triple input = new Triple(1, 2, 3); if (input instanceof Triple t) { System.out.println("Made it here"); } } } And here is the warning. $ javac -Xlint:preview --enable-preview --release 19 UnconditionalPatternsPreviewWarning.java UnconditionalPatternsPreviewWarning.java:15: warning: [preview] unconditional patterns in instanceof are a preview feature and may be removed in a future release. if (input instanceof Triple t) ^ 1 warning I tried searching for what this warning means, but couldn't find it. More specifically, I couldn't understand what Unconditional Patterns meant. With some help from StackOverflow (https://stackoverflow.com/questions/74978665), I was led to a blog by Nicolai Parlog, which explained the meaning. > ...an unconditional pattern, that is, a > pattern that matches all possible > instances of the switched variable?s type. I understand the meaning well enough. Basically, it is saying that the compiler knows 100% that a variable is fully and unconditionally matched by the given pattern. Therefore, it is considered an unconditional pattern. As a result, since unconditional patterns are in preview (while instanceof pattern-matching has since been released as General Availability), then I now understand my warning and why it occurred. But that leads to a couple questions. The fact that you all made this delineation meant that it is something worth denoting. Why? What about it is so significant that you would denote this? In fact, if I turn off the --enable-preview features flag and the Xlint check, that warning turns into an error for the exact same reason -- my pattern fully encompasses all possible values of my variable. So this is clearly something that needed a big fence put around it. Is there some (upcoming) functionality involving pattern-matching that depends on this delineation? Why make this delineation for the following snippet, but not the one below it? if (input instanceof Triple t) {} //error or warning, depending on what you compile with if (input instanceof Triple) {} //compiles fine and runs fine Is it because of backwards compatibility? Thank you all for your time and your help! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From merlin.boegershausen at rwth-aachen.de Mon Jan 2 08:03:03 2023 From: merlin.boegershausen at rwth-aachen.de (=?utf-8?B?QsO2Z2Vyc2hhdXNlbiwgTWVybGlu?=) Date: Mon, 2 Jan 2023 08:03:03 +0000 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: References: Message-ID: Hi, I can confirm this for Eclipse Adoptium 19.0.1+10 and Eclipse Adoptium 17.0.5+8 on MacOS with your code. I am with you that it looks strange as since JEP 394 [1] instance of Pattern is a permanent features and input instanceof Triple t seems like such. But the error message points us to UnconditionalPatterns and in my case to the subtype Triple and Triple Deconstruction Patterns are in Preview with JEP 433. Is it possible that the Compiler interprets instance of Patterns with Record Classes as Record Patterns? Nerveless your last Question regarding why input instanceof Triple t raises an error but input instanceof Triple is simpler. The latter is not a Pattern, it?s a Boolean expression and is a permanent feature since the introduction of instance of. For the record I am not part of the Dev team, I am ?only? part of the consuming community ? Best Merlin [1] https://openjdk.org/jeps/394 [2] https://openjdk.org/jeps/433 Merlin B?gershausen E: Merlin.Boegershausen at rwth-aachen.de W: https://mboegers.github.io Von: amber-dev im Auftrag von David Alayachew Datum: Montag, 2. Januar 2023 um 05:56 An: amber-dev Betreff: I am having trouble understanding the purpose of Unconditional Patterns Hello Amber Dev Team, I was working on some code using Pattern-Matching for instanceof, and then I ran into a surprising warning. Here is the code. public class UnconditionalPatternsPreviewWarning { public record Triple(int a, int b, int c) {} public static void main(String[] args) { System.out.println("Java Version = " + System.getProperty("java.version")); final Triple input = new Triple(1, 2, 3); if (input instanceof Triple t) { System.out.println("Made it here"); } } } And here is the warning. $ javac -Xlint:preview --enable-preview --release 19 UnconditionalPatternsPreviewWarning.java UnconditionalPatternsPreviewWarning.java:15: warning: [preview] unconditional patterns in instanceof are a preview feature and may be removed in a future release. if (input instanceof Triple t) ^ 1 warning I tried searching for what this warning means, but couldn't find it. More specifically, I couldn't understand what Unconditional Patterns meant. With some help from StackOverflow (https://stackoverflow.com/questions/74978665), I was led to a blog by Nicolai Parlog, which explained the meaning. > ...an unconditional pattern, that is, a > pattern that matches all possible > instances of the switched variable?s type. I understand the meaning well enough. Basically, it is saying that the compiler knows 100% that a variable is fully and unconditionally matched by the given pattern. Therefore, it is considered an unconditional pattern. As a result, since unconditional patterns are in preview (while instanceof pattern-matching has since been released as General Availability), then I now understand my warning and why it occurred. But that leads to a couple questions. The fact that you all made this delineation meant that it is something worth denoting. Why? What about it is so significant that you would denote this? In fact, if I turn off the --enable-preview features flag and the Xlint check, that warning turns into an error for the exact same reason -- my pattern fully encompasses all possible values of my variable. So this is clearly something that needed a big fence put around it. Is there some (upcoming) functionality involving pattern-matching that depends on this delineation? Why make this delineation for the following snippet, but not the one below it? if (input instanceof Triple t) {} //error or warning, depending on what you compile with if (input instanceof Triple) {} //compiles fine and runs fine Is it because of backwards compatibility? Thank you all for your time and your help! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 2 13:51:20 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Mon, 2 Jan 2023 08:51:20 -0500 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: References: Message-ID: Hello Merlin, > I can confirm this for Eclipse Adoptium > 19.0.1+10 and Eclipse Adoptium 17.0.5+8 > on MacOS with your code. Thank you for the confirmation. I have been running into configuration errors all day, so I am glad this isn't some mistake on my part. > Nerveless your last Question regarding > why input instanceof Triple t raises an > error but input instanceof Triple is > simpler. The latter is not a Pattern, > it?s a Boolean expression and is a > permanent feature since the > introduction of instance of. Thank you for clarifying. Ok, that is good to know. So, in short, the reason why this distinction exists between instanceof the original and instanceof pattern match is because the old functionality has not changed at all. Which does lead into the next question nicely. > Is it possible that the Compiler > interprets instance of Patterns with > Record Classes as Record Patterns? This was my first instinct as well, but since this error message is so directed with a very specific, new piece of vocabulary, it sounds unlikely. Plus, the blog I linked written by Nicolai Parlog used an example involving String and Object, neither of which is a record. Still, this did clarify a lot for me and helped me understand things better. Thank you for your help and insight! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 2 13:56:04 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Mon, 2 Jan 2023 08:56:04 -0500 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: References: Message-ID: Whoops, I don't think I ever did link the blog from Nicolai Parlog. Here it is -- https://blogs.oracle.com/javamagazine/post/java-pattern-matching-switch-when-null Also, here is the StackOverflow post I made with the best understanding I could make of Unconditional Patterns. https://stackoverflow.com/questions/74978988/what-are-unconditional-patterns-java-19-preview-unconditional-patterns-in-i If you, or anyone else, has some better insight on the subject, please feel free to let me know here or on the StackOverflow. Since this is a subject that is hard to research, I feel like adding to that post will be valuable. Maybe I am wrong though, since this is a preview feature. Thank you again for your help and support! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jan 2 16:19:23 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 2 Jan 2023 16:19:23 +0000 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: References: Message-ID: <3CA61530-0AF3-454B-A6BB-10037720C0B3@oracle.com> Mostly, the warning is confusing. In an earlier preview, unconditional patterns were prohibited in instanceof because we were concerned of an asymmetry between `instanceof X` and `instanceof X x`. The asymmetry was resolved and unconditional patterns were allowed there, but the warning is still a little confusing. The fact that you all made this delineation meant that it is something worth denoting. Is there some (upcoming) functionality involving pattern-matching that depends on this delineation? Unconditionality is the basic building block of exhaustiveness (and pattern dominance.) Note that unconditionality is a stronger condition than exhaustiveness, for reasons that have been explained in other mails. Why make this delineation for the following snippet, but not the one below it? if (input instanceof Triple t) {} //error or warning, depending on what you compile with if (input instanceof Triple) {} //compiles fine and runs fine These should mean the same thing now. (Originally it did not, and we were worried this would be confusing, hence the restriction.) The main place where they didn?t was at null, and finding the right place to handle nullity was among the trickiest aspects of getting this design result. Now, the construct (instanceof, switch, etc) gets first crack at the target, and gets to have opinions about nulls, and whether/when to proceed and try to match the pattern. So instanceof first checks for null and short circuits to false in that case, and if not, it tries to match the pattern. (If the pattern is unconditional on the operand type no runtime test should be generated.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 2 16:55:45 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Mon, 2 Jan 2023 11:55:45 -0500 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: <3CA61530-0AF3-454B-A6BB-10037720C0B3@oracle.com> References: <3CA61530-0AF3-454B-A6BB-10037720C0B3@oracle.com> Message-ID: Hello Brian, > Mostly, the warning is confusing. In an > earlier preview, unconditional patterns > were prohibited in instanceof because we > were concerned of an asymmetry between > `instanceof X` and `instanceof X x`. The > asymmetry was resolved and unconditional > patterns were allowed there Thank you for your response. I understand now why the warning was put there in the first place - to prevent a potential point of confusion for users until the creases were ironed out. I also understand the pain points involving null and making sure that they are handled properly in instanceof patterns and switch patterns. I do appreciate how we can handle null neatly in both, with null just returning false in instanceof, and case null being an option to us for switch patterns. > Unconditionality is the basic building > block of exhaustiveness (and pattern > dominance.) > > Note that unconditionality is a stronger > condition than exhaustiveness, for reasons > that have been explained in other mails. If I understand correctly, this is sort of like how we use ::add as the building block of ::addAll. More specifically, we enforce pattern dominance in switch patterns by ensuring that the pattern above is not unconditional for the pattern below. And we can enforce exhaustiveness by making sure the final pattern in switch patterns is the only one that is unconditional on the parameter. Please correct me if either of those 2 is wrong. > These should mean the same thing now. I guess this is where my primary point of confusion is now. It sounds like the creases have been ironed out at this point between instanceof pattern matching and unconditionality. So why does the warning still exist for instanceof pattern matching? I would understand if this was for other forms of pattern matching, since those may not have an answer to unconditionality yet. But it sounds like you are telling me that instanceof does. And I don't think it is related to the fact that I am doing this for a record. I tested this on a String too and ran into the exact same problem. final String s = "s"; if (s instanceof String output) { System.out.println("String match"); } UnconditionalPatternsPreviewWarning.java:15: warning: [preview] unconditional patterns in instanceof are a preview feature and may be removed in a future release. if (s instanceof String output) ^ 1 warning Thank you for your help and insight! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jan 2 17:17:58 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 2 Jan 2023 17:17:58 +0000 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: References: <3CA61530-0AF3-454B-A6BB-10037720C0B3@oracle.com> Message-ID: <1AA9CA98-1755-4FE6-8C30-509157FBD764@oracle.com> More specifically, we enforce pattern dominance in switch patterns by ensuring that the pattern above is not unconditional for the pattern below. Essentially yes, though its more subtle than that. But where unconditionality is really important is in nesting. Suppose I have record Box(Object o) { ? } and switch (box) { case Box(Object o): B; case Box b: // dead } We can conclude the second pattern is dominated because not only is there a ?case Box(?)? above it, but the pattern nested inside it (Object o) is unconditional on the component of Box. If the first pattern were `case Box(Integer i)`, the `case Box b` would not be dead. And we can enforce exhaustiveness by making sure the final pattern in switch patterns is the only one that is unconditional on the parameter. That?s one way to get exhaustiveness, but not the only way. If I have a sealed type A = B|C, then if the switch exhausts B and C, then it exhausts A, even without any sort of `case A` pattern. It sounds like the creases have been ironed out at this point between instanceof pattern matching and unconditionality. So why does the warning still exist for instanceof pattern matching? As I said, the warning is confusingly worded, and will go away when we exit preview (which is hopefully soon.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 2 17:29:14 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Mon, 2 Jan 2023 12:29:14 -0500 Subject: I am having trouble understanding the purpose of Unconditional Patterns In-Reply-To: <1AA9CA98-1755-4FE6-8C30-509157FBD764@oracle.com> References: <3CA61530-0AF3-454B-A6BB-10037720C0B3@oracle.com> <1AA9CA98-1755-4FE6-8C30-509157FBD764@oracle.com> Message-ID: Hello Brian, I appreciate the context for how unconditionality plays with instance of and switch. There's a lot more depth than what appears on the surface. > As I said, the warning is confusingly worded, and will go away when we exit preview (which is hopefully soon.) Whoops, I understand now. So, since unconditionality has been ironed out, what I was trying to do will likely will be the final implementation of unconditional patterns. However, unconditional patterns are still a preview feature, hence the warning. That has nothing to do with the fact that instanceof pattern matching has long since exited preview. These are 2 different things. I understand now, thank you. Is there somewhere on the JEP 0 website or somewhere else where we can read more on this? I am so used to seeing a JEP for these, so my assumption that there would be some JEP to delineate this added to my confusion. Thank you for the help and clarification! David Alayachew -------------- next part -------------- An HTML attachment was scrubbed... URL: From duke at openjdk.org Tue Jan 3 09:40:20 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:40:20 GMT Subject: [stats-before-this-super] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Thu, 6 Jan 2022 22:02:02 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 39 commits from the branch `master`that can **not** be merged into the branch `stats-before-this-super`: > > The following file contains merge conflicts: > > - .jcheck/conf > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout stats-before-this-super > $ git pull https://github.com/openjdk/amber.git stats-before-this-super > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +80:openjdk-bot-80 > $ git checkout openjdk-bot-80 > > # Merge the target branch > $ git merge stats-before-this-super > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-80:80 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/78 From duke at openjdk.org Tue Jan 3 09:42:28 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:42:28 GMT Subject: [concise-method-declarations] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Thu, 14 Jan 2021 22:00:46 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 133 commits from the branch `master`that can **not** be merged into the branch `concise-method-declarations`: > > The following file contains merge conflicts: > > - src/jdk.compiler/share/classes/com/sun/tools/javac/resources/compiler.properties > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout concise-method-declarations > $ git pull https://github.com/openjdk/amber.git concise-method-declarations > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +78:openjdk-bot-78 > $ git checkout openjdk-bot-78 > > # Merge the target branch > $ git merge concise-method-declarations > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-78:78 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/76 From duke at openjdk.org Tue Jan 3 09:43:30 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:43:30 GMT Subject: [lambda-leftovers] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Thu, 31 Dec 2020 22:02:23 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 10 commits from the branch `master`that can **not** be merged into the branch `lambda-leftovers`: > > The following file contains merge conflicts: > > - test/langtools/tools/javac/lambda/UnderscoreAsIdent.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout lambda-leftovers > $ git pull https://github.com/openjdk/amber.git lambda-leftovers > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +78:openjdk-bot-78 > $ git checkout openjdk-bot-78 > > # Merge the target branch > $ git merge lambda-leftovers > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-78:78 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/75 From duke at openjdk.org Tue Jan 3 09:44:32 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:44:32 GMT Subject: [sealed-types] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Thu, 26 Nov 2020 22:03:14 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 129 commits from the branch `master`that can **not** be merged into the branch `sealed-types`: > > The following file contains merge conflicts: > > - src/java.base/share/classes/java/lang/Package.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout sealed-types > $ git pull https://github.com/openjdk/amber.git sealed-types > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +75:openjdk-bot-75 > $ git checkout openjdk-bot-75 > > # Merge the target branch > $ git merge sealed-types > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-75:75 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/72 From duke at openjdk.org Tue Jan 3 09:45:20 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:45:20 GMT Subject: [records-2] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Thu, 12 Nov 2020 22:01:00 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 87 commits from the branch `master`that can **not** be merged into the branch `records-2`: > > The following file contains merge conflicts: > > - test/langtools/tools/javac/records/RecordsBinaryCompatibilityTests.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout records-2 > $ git pull https://github.com/openjdk/amber.git records-2 > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +74:openjdk-bot-74 > $ git checkout openjdk-bot-74 > > # Merge the target branch > $ git merge records-2 > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-74:74 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/71 From duke at openjdk.org Tue Jan 3 09:47:17 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:47:17 GMT Subject: [patterns-stage-2] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Tue, 10 Nov 2020 15:09:15 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 380 commits from the branch `master`that can **not** be merged into the branch `patterns-stage-2`: > > The following files contains merge conflicts: > > - src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout patterns-stage-2 > $ git pull https://github.com/openjdk/amber.git patterns-stage-2 > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +73:openjdk-bot-73 > $ git checkout openjdk-bot-73 > > # Merge the target branch > $ git merge patterns-stage-2 > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-73:73 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/70 From duke at openjdk.org Tue Jan 3 09:48:21 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:48:21 GMT Subject: [pattern-runtime] Withdrawn: Merge master In-Reply-To: <8EP8468ce1OflIyCvdMSJmojxDrX6TkR88Ev6OTDBao=.cbebfa6f-389b-469f-93f2-c837260896c2@github.com> References: <8EP8468ce1OflIyCvdMSJmojxDrX6TkR88Ev6OTDBao=.cbebfa6f-389b-469f-93f2-c837260896c2@github.com> Message-ID: On Tue, 10 Nov 2020 15:08:54 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 134 commits from the branch `master`that can **not** be merged into the branch `pattern-runtime`: > > The following files contains merge conflicts: > > - src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout pattern-runtime > $ git pull https://github.com/openjdk/amber.git pattern-runtime > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +72:openjdk-bot-72 > $ git checkout openjdk-bot-72 > > # Merge the target branch > $ git merge pattern-runtime > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-72:72 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/69 From duke at openjdk.org Tue Jan 3 09:49:24 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:49:24 GMT Subject: [enhanced-enums] Withdrawn: Merge master In-Reply-To: References: Message-ID: On Tue, 10 Nov 2020 15:08:04 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 134 commits from the branch `master`that can **not** be merged into the branch `enhanced-enums`: > > The following files contains merge conflicts: > > - src/jdk.compiler/share/classes/com/sun/tools/javac/code/Preview.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/TransPatterns.java > - src/jdk.compiler/share/classes/com/sun/tools/javac/parser/JavacParser.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout enhanced-enums > $ git pull https://github.com/openjdk/amber.git enhanced-enums > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +71:openjdk-bot-71 > $ git checkout openjdk-bot-71 > > # Merge the target branch > $ git merge enhanced-enums > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-71:71 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/68 From duke at openjdk.org Tue Jan 3 09:50:10 2023 From: duke at openjdk.org (duke) Date: Tue, 3 Jan 2023 09:50:10 GMT Subject: [local-methods] Withdrawn: Merge master In-Reply-To: <2kSTnD7GyyydKlg-GE9dC8MnKbigX4o_dmDAu6XkuG4=.78d524ee-04ab-41d1-88db-b2c9541fe947@github.com> References: <2kSTnD7GyyydKlg-GE9dC8MnKbigX4o_dmDAu6XkuG4=.78d524ee-04ab-41d1-88db-b2c9541fe947@github.com> Message-ID: <8_rYHxHHkRLKTEhepz5hL17m1GGH5A8On9U6MfiRcok=.cdba1654-0e7e-4291-9bc4-7827a8231b74@github.com> On Tue, 10 Nov 2020 15:07:26 GMT, J. Duke wrote: > Hi all, > > this is an _automatically_ generated pull request to notify you that there are 134 commits from the branch `master`that can **not** be merged into the branch `local-methods`: > > The following file contains merge conflicts: > > - src/jdk.compiler/share/classes/com/sun/tools/javac/comp/Attr.java > > All Committers in this [project](https://openjdk.java.net/census#amber) have access to my [personal fork](https://github.com/openjdk-bot/amber) and can therefore help resolve these merge conflicts (you may want to coordinate who should do this). > The following paragraphs will give an example on how to solve these merge conflicts and push the resulting merge commit to this pull request. > The below commands should be run in a local clone of your [personal fork](https://wiki.openjdk.java.net/display/skara#Skara-Personalforks) of the [openjdk/amber](https://github.com/openjdk/amber) repository. > > > # Ensure target branch is up to date > $ git checkout local-methods > $ git pull https://github.com/openjdk/amber.git local-methods > > # Fetch and checkout the branch for this pull request > $ git fetch https://github.com/openjdk-bot/amber.git +68:openjdk-bot-68 > $ git checkout openjdk-bot-68 > > # Merge the target branch > $ git merge local-methods > > > When you have resolved the conflicts resulting from the `git merge` command above, run the following commands to create a merge commit: > > > $ git add paths/to/files/with/conflicts > $ git commit -m 'Merge master' > > > > When you have created the merge commit, run the following command to push the merge commit to this pull request: > > > $ git push https://github.com/openjdk-bot/amber.git openjdk-bot-68:68 > > > _Note_: if you are using SSH to push commits to GitHub, then change the URL in the above `git push` command accordingly. > > Thanks, > J. Duke This pull request has been closed without being integrated. ------------- PR: https://git.openjdk.org/amber/pull/67 From archie.cobbs at gmail.com Wed Jan 4 18:23:34 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 4 Jan 2023 12:23:34 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> Message-ID: Sorry for the slow response due to vacation... On Fri, Dec 30, 2022 at 1:00 PM Brian Goetz wrote: > > One thing that makes me a little uncomfortable is that @SW usually is used >> to say ?the compiler can?t prove this is safe, but I am asserting it is.? >> But this is different; the compiler has discovered the class is unsafe, >> and @SW is saying ?I know, I know, stop telling me.? So I think there?s an >> additional documentation opportunity here where, for the classes we had to >> annotate with @SW, we include an additional @apiNote of the form ?This >> class behaves badly, oops?, with a link to a common doc page explaining the >> problem. (While we don?t have to do this necessarily immediately, the >> chance of it falling on the floor if we don?t are higher.). Basically, what >> you?ve identified is that there are a number of classes in the JDK which >> fail to follow best practices with regard to self-use from constructors. >> We can?t turn back the clock, but we can mark these as ?don?t code like my >> brother?, so people see these patterns of coding and realize they are not >> to be emulated. >> > > Good point. > > I think it's also worth considering which scenarios require such > documentation. We have drawn the "boundary lines" at the compilation unit > boundary, but this means (for example) there are package-private classes > that generate warnings. Because these classes will end up in a module, > which requires special effort to crack open, the warnings only really apply > to JDK developers working in that same package. > > > For package-private classes, we should know all the subclasses, and > therefore may have the opportunity to seal it. Then we are not subject to > ?arbitrary subclass might do X?, but only ?these specific subclasses do X.? > So perhaps this is an opportunity to make final / seal some > package-private classes that don?t need extensibility. > Yes, there are probably a bunch of classes out there that could be made 'final'. Seems like this would make for a good follow-up change. Another consideration regarding @apiNote is how likely the problem really is. For example, several warnings come from code like this: private PropertyChangeSupport support = new PropertyChangeSupport(this); Yes, it's possible in theory that PropertyChangeSupport could someday be modified to invoke some method of 'this', but in reality we know all it does is stash 'this' in a field and return and that's not likely to change anytime soon. Not much to be gained from including an @apiNote warning in those cases. At any rate, I did a pass through and updated these "popular" classes with leaky constructors with a Javadoc note: java/io/PipedReader.java java/io/PipedWriter.java java/lang/Throwable.java java/util/ArrayDeque.java java/util/EnumMap.java java/util/HashSet.java java/util/Hashtable.java java/util/LinkedList.java java/util/TreeMap.java java/util/TreeSet.java You can see these changes in this commit . FYI, I used @implNote instead of @apiNote because this seemed like more of an implementation issue than an API issue (but please correct me if I'm wrong). > > From what I can tell, these are leftovers from about 10 years ago when > some developers were using NetBeans, which had just such a warning. I don't > think they are relevant any more but I didn't want to presume anything so I > left them in there. > > > So, LTIC is not a lint category of javac? When Jan gets back from break, > maybe he can shed some more light on this. But unless we have a good > reason to keep the LTICs, we should consider garbage-collecting them. > "LeakingThisInConstructor" is definitely not a current lint category for javac. I've replaced it with "this-escape". I ran across another one as well: "OverridableMethodCallInConstructor" (in src/demo/share/jfc/Notepad/Notepad.java). Also, since the last post I found and fixed a few bugs, which revealed more 'this' escapes. Here are the new numbers, which have gone up a bit: #SUPPRESS #FILES MODULE 207 3076 java.base 0 128 java.compiler 4 18 java.datatransfer 475 2899 java.desktop 0 10 java.instrument 9 23 java.logging 52 330 java.management 0 16 java.management.rmi 15 199 java.naming 32 142 java.net.http 0 20 java.prefs 14 106 java.rmi 0 15 java.scripting 0 1 java.se 46 216 java.security.jgss 1 30 java.security.sasl 0 23 java.smartcardio 13 77 java.sql 6 56 java.sql.rowset 0 5 java.transaction.xa 277 1848 java.xml 70 271 java.xml.crypto 3 20 jdk.accessibility 1 21 jdk.attach 1 18 jdk.charsets 84 333 jdk.compiler 2 76 jdk.crypto.cryptoki 4 35 jdk.crypto.ec 1 11 jdk.crypto.mscapi 7 68 jdk.dynalink 0 3 jdk.editpad 120 942 jdk.hotspot.agent 5 56 jdk.httpserver 0 5 jdk.incubator.concurrent 0 50 jdk.incubator.vector 0 3 jdk.internal.ed 8 61 jdk.internal.jvmstat 16 113 jdk.internal.le 4 52 jdk.internal.opt 5 209 jdk.internal.vm.ci 0 1 jdk.internal.vm.compiler 0 1 jdk.internal.vm.compiler.management 0 18 jdk.jartool 20 228 jdk.javadoc 1 41 jdk.jcmd 44 64 jdk.jconsole 23 124 jdk.jdeps 44 254 jdk.jdi 0 1 jdk.jdwp.agent 0 263 jdk.jfr 2 77 jdk.jlink 5 80 jdk.jpackage 8 88 jdk.jshell 0 4 jdk.jsobject 2 11 jdk.jstatd 2 281 jdk.localedata 1 25 jdk.management 0 19 jdk.management.agent 0 15 jdk.management.jfr 1 16 jdk.naming.dns 0 8 jdk.naming.rmi 0 11 jdk.net 0 2 jdk.nio.mapmode 0 11 jdk.random 1 37 jdk.sctp 0 30 jdk.security.auth 0 16 jdk.security.jgss 0 9 jdk.unsupported 0 8 jdk.unsupported.desktop 0 94 jdk.xml.dom 1 14 jdk.zipfs -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 4 19:23:53 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 4 Jan 2023 19:23:53 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> Message-ID: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Another consideration regarding @apiNote is how likely the problem really is. For example, several warnings come from code like this: private PropertyChangeSupport support = new PropertyChangeSupport(this); Yes, it's possible in theory that PropertyChangeSupport could someday be modified to invoke some method of 'this', but in reality we know all it does is stash 'this' in a field and return and that's not likely to change anytime soon. Not much to be gained from including an @apiNote warning in those cases. Yeah, this is a mess. The set of conditions that one would have to check to prove this safe is large, and spans both the behavior of PCS and the client. If we are convinced that _specific uses_ of this are OK, then that?s a reasonable place to use @SW without further note, but for things like the ArrayList constructors that call add, this is fundamentally dangerous and probably wants a note. FYI, I used @implNote instead of @apiNote because this seemed like more of an implementation issue than an API issue (but please correct me if I'm wrong). It?s on the fence?. Also, since the last post I found and fixed a few bugs, which revealed more 'this' escapes. Here are the new numbers, which have gone up a bit: Are there interesting examples of the new form that we didn?t detect before, that would be educational to share? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 4 20:27:13 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 4 Jan 2023 14:27:13 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Message-ID: On Wed, Jan 4, 2023 at 1:23 PM Brian Goetz wrote: > > for things like the ArrayList constructors that call add, this is > fundamentally dangerous and probably wants a note. > > Agreed... except ArrayList is a bad example :) ArrayList(Collection c) actually does not invoke add() or addAll(). Instead it invokes c.toArray(). > Also, since the last post I found and fixed a few bugs, which revealed > more 'this' escapes. Here are the new numbers, which have gone up a bit: > > > Are there interesting examples of the new form that we didn?t detect > before, that would be educational to share? > Not really - the increase was just due to a dumb bug in which unqualified method invocations like "foo()" were not always being caught. In general though, from what I can tell, most leaks are pretty much what you might expect. Many of them fall into the bucket of "Yes this is a leak, but it's unlikely to cause trouble in practice." But there are definitely some "dangerous" ones too, such as HashSet, etc. The most common pattern for leaks is invoking some non-static method in the constructor. For example, lots of classes invoke some kind of init() method or whatever. Basically the constructor needs to do some work, and for whatever reason (some part of) that work has been abstracted out into a separate method or lives in a superclass. For example, lots of Swing widget constructors invoke methods like setLayout(), setBackground(), setBorder(), etc. Several exception classes invoke initCause() (and of course Throwable is guilty of invoking fillInStackTrace(), which is not final). Several classes invoke CleanerFactory.cleaner().register(this, ...). In short this warning, like a lot of the other lint warnings, seems to fall into the category that you're likely to get false positives, but that's hopefully worth it in exchange for a new category of automated bug detection. What are the next steps? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 5 15:25:43 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 5 Jan 2023 15:25:43 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Message-ID: Next steps: - Figure out what we are going to say for the cases where we @SW but want to indicate that things are not indeed safe. I think the way to do this is to write a short explanation of the this-escape problem on an HTML page in the doc set, and come up with a suitably scary one-sentence @implNote that links to it. - Get the code reviewed, and make sure the implementation is in line with how we are doing larger lint analysis these days (I know this has evolved over time.). On Jan 4, 2023, at 3:27 PM, Archie Cobbs > wrote: What are the next steps? -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 5 18:24:15 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 5 Jan 2023 12:24:15 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Message-ID: On Thu, Jan 5, 2023 at 9:25 AM Brian Goetz wrote: > - Figure out what we are going to say for the cases where we @SW but want > to indicate that things are not indeed safe. I think the way to do this > is to write a short explanation of the this-escape problem on an HTML page > in the doc set, and come up with a suitably scary one-sentence @implNote > that links to it. > Sounds good. Please see ThisEscape.html and commit 9d45b4d5 . > - Get the code reviewed, and make sure the implementation is in line with > how we are doing larger lint analysis these days (I know this has evolved > over time.). > Sounds good. Can you suggest (or even better, help encourage) some reviewer(s)? Unfortunately, based on past experience, I'm pretty sure if I just ask for volunteers on compiler-dev myself it's likely such a request will be ignored. More generally, at this point do we need to recruit other folks to the cause (so to speak)? Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 5 18:36:07 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 5 Jan 2023 18:36:07 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <140e133e-4c46-5d83-1ccf-32e40406a13a@oracle.com> <362d1d7b-97fe-dc2e-de02-1d0169bd2626@oracle.com> <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Message-ID: > Sounds good. Can you suggest (or even better, help encourage) some reviewer(s)? It sounds like Vicente is already starting to look at this. Joe Darcy, who led the ?warnings cleanup? effort, is going to take a look as well. From vicente.romero at oracle.com Thu Jan 5 19:06:47 2023 From: vicente.romero at oracle.com (Vicente Romero) Date: Thu, 5 Jan 2023 14:06:47 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> Message-ID: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Hi Archie, yep I've been reviewing other PRs you have been working on, this one is also in my list, Vicente On 1/5/23 13:36, Brian Goetz wrote: >> Sounds good. Can you suggest (or even better, help encourage) some reviewer(s)? > It sounds like Vicente is already starting to look at this. Joe Darcy, who led the ?warnings cleanup? effort, is going to take a look as well. > > From archie.cobbs at gmail.com Thu Jan 5 19:20:07 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 5 Jan 2023 13:20:07 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> References: <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: On Thu, Jan 5, 2023 at 1:06 PM Vicente Romero wrote: > yep I've been reviewing other PRs you have been working on, this one is > also in my list, > Hi Vicente, Awesome! Thanks very much. Just to be clear, there aren't PR's filed yet for the 'this' escape work, or for the related work allowing code before super(). Just let me know if/when I should do that. Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Thu Jan 5 19:22:40 2023 From: vicente.romero at oracle.com (Vicente Romero) Date: Thu, 5 Jan 2023 14:22:40 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: On 1/5/23 14:20, Archie Cobbs wrote: > On Thu, Jan 5, 2023 at 1:06 PM Vicente Romero > wrote: > > yep I've been reviewing other PRs you have been working on, this > one is > also in my list, > > > Hi Vicente, > > Awesome! Thanks very much. > > Just to be clear, there aren't PR's filed yet for the 'this' escape > work, or for the related work allowing code before super(). Just let > me know if/when I should do that. I saw a fork with some related code but feel free to condense the work in a formal PR > > Thanks, > -Archie > > -- > Archie L. Cobbs Vicente -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 5 19:59:43 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 5 Jan 2023 13:59:43 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: On Thu, Jan 5, 2023 at 1:22 PM Vicente Romero wrote: > > On 1/5/23 14:20, Archie Cobbs wrote: > > On Thu, Jan 5, 2023 at 1:06 PM Vicente Romero > wrote: > >> yep I've been reviewing other PRs you have been working on, this one is >> also in my list, >> > > Just to be clear, there aren't PR's filed yet for the 'this' escape work, > or for the related work allowing code before super(). Just let me know > if/when I should do that. > > > I saw a fork with some related code but feel free to condense the work in > a formal PR > OK great - thanks. For the 'this' escape, it looks like the following JDK bugs would be fixed, so I'll plan to file the PR under one of these: JDK-8015831 JDK-6557145 FWIW, the following bugs are related, but not (necessarily) fixed: JDK-6563146 JDK-8091094 For the code before super() work (JDK-8194743 ), is it OK to file a PR before there is a JEP? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Wed Jan 11 16:23:09 2023 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 11 Jan 2023 11:23:09 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Hi, On 1/5/23 14:59, Archie Cobbs wrote: > On Thu, Jan 5, 2023 at 1:22 PM Vicente Romero > wrote: > > > On 1/5/23 14:20, Archie Cobbs wrote: >> On Thu, Jan 5, 2023 at 1:06 PM Vicente Romero >> wrote: >> >> yep I've been reviewing other PRs you have been working on, >> this one is >> also in my list, >> >> >> Just to be clear, there aren't PR's filed yet for the 'this' >> escape work, or for the related work allowing code before >> super(). Just let me know if/when I should do that. > > I saw a fork with some related code but feel free to condense the > work in a formal PR > > > OK great - thanks. > > For the 'this' escape, it looks like the following JDK bugs would be > fixed, so I'll plan to file the PR under one of these: > > JDK-8015831 > JDK-6557145 > > FWIW, the following bugs are related, but not (necessarily) fixed: > > JDK-6563146 > JDK-8091094 > > For the code before super() work (JDK-8194743 > ), is it OK to file a PR > before there is a JEP? it could be done either way but I think that going for the JEP first is usually a better approach > > -Archie > > -- > Archie L. Cobbs Vicente -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Jan 16 18:02:13 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 16 Jan 2023 12:02:13 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: Regarding 'this' escape, folks may have already seen the blizzard of PR comments but I thought I'd pull out this one from @mcimadamore as particularly interesting from a design perspective: To be fair, this is what my brain was reading when you talked about > "compilation unit" - but then saw that the code was doing it differently. > You see, for "sealed" classes we have a notion of "maintenance domain". > E.g. the classes in a permits clause of a sealed declaration must belong > to the same module (if available) or same package (if no module is > available). That's how you get the exhaustiveness analysis and all the > goodies, by essentially making a close-world assumption on the classes that > are passed to javac for a given compilation task. I think it would make a > lot of sense to apply these very same boundaries to the escape-this > analysis (and, in fact, when looking at warnings coming out of the JDK, I > often found false positives that were caused by this). > Any thoughts? Should we define the "boundary of concern" differently for sealed classes? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jan 16 18:45:10 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 16 Jan 2023 13:45:10 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> Message-ID: <2cfe9abb-a472-0e4d-7688-52da0960297f@oracle.com> This is an interesting one. The design of sealed classes deliberately took the unit of maintenance into account: in the unnamed module, they must be the same package, and in a named module, they must be in the same module.? I am not sure if we require that they always be co-compiled; if we already do, then having the analysis cross the boundary makes sense, but if we permit a sealed nest to be compiled separately, then it might be weird to only do the this-escape analysis if they happen to be being co-compiled? On 1/16/2023 1:02 PM, Archie Cobbs wrote: > Regarding 'this' escape, folks may have already seen the blizzard of > PR comments but I thought I'd pull out this one > > from @mcimadamore as particularly interesting from a design perspective: > > To be fair, this is what my brain was reading when you talked > about "compilation unit" - but then saw that the code was doing it > differently. You see, for "sealed" classes we have a notion of > "maintenance domain". E.g. the classes in a |permits| clause of a > |sealed| declaration must belong to the same module (if available) > or same package (if no module is available). That's how you get > the exhaustiveness analysis and all the goodies, by essentially > making a close-world assumption on the classes that are passed to > javac for a given compilation task. I think it would make a lot of > sense to apply these very same boundaries to the escape-this > analysis (and, in fact, when looking at warnings coming out of the > JDK, I often found false positives that were caused by this). > > > Any thoughts? Should we define the "boundary of concern" differently > for sealed classes? > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Tue Jan 17 00:10:03 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 16 Jan 2023 18:10:03 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <2cfe9abb-a472-0e4d-7688-52da0960297f@oracle.com> References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <2cfe9abb-a472-0e4d-7688-52da0960297f@oracle.com> Message-ID: Hmm.. I think we can do something pretty close to what @mcimadamore is proposing in a way that doesn't care how the compilation is performed. The requirement is to be able to look at some class X being compiled and decide whether any subclasses of X could exist outside of its "maintenance domain". Currently, we have maintenance domain = the compilation unit (i.e., the file X.java). In this case we ask: Is X not final, not sealed (or, sealed but permitting some class defined outside of X.java), and does X have a non-private constructor? In the definition that @mcimadamore is proposing, we could ask: Is X public, not final, not sealed, and does X have a non-private constructor? Ideally we'd also ask "Is X's package exported by its module, if any?" but now you're making assumptions about how the code is being compiled. But even without that, the above criteria should get you pretty close I would guess. The tangible benefit here is exemplified by the reduction in JDK warnings from 2093 to 1334 (36%) when you use the tighter criteria. I'm thinking since this is a new warning, we should err on the side of less aggressiveness, but then we can dial it up over time if needed. Kind of like how GCC's -Wcast-qual has gotten more and more picky over the years (it seems). -Archie On Mon, Jan 16, 2023 at 12:45 PM Brian Goetz wrote: > This is an interesting one. The design of sealed classes deliberately > took the unit of maintenance into account: in the unnamed module, they must > be the same package, and in a named module, they must be in the same > module. I am not sure if we require that they always be co-compiled; if we > already do, then having the analysis cross the boundary makes sense, but if > we permit a sealed nest to be compiled separately, then it might be weird > to only do the this-escape analysis if they happen to be being co-compiled? > > On 1/16/2023 1:02 PM, Archie Cobbs wrote: > > Regarding 'this' escape, folks may have already seen the blizzard of PR > comments but I thought I'd pull out this one > > from @mcimadamore as particularly interesting from a design perspective: > > To be fair, this is what my brain was reading when you talked about >> "compilation unit" - but then saw that the code was doing it differently. >> You see, for "sealed" classes we have a notion of "maintenance domain". >> E.g. the classes in a permits clause of a sealed declaration must belong >> to the same module (if available) or same package (if no module is >> available). That's how you get the exhaustiveness analysis and all the >> goodies, by essentially making a close-world assumption on the classes that >> are passed to javac for a given compilation task. I think it would make a >> lot of sense to apply these very same boundaries to the escape-this >> analysis (and, in fact, when looking at warnings coming out of the JDK, I >> often found false positives that were caused by this). >> > > Any thoughts? Should we define the "boundary of concern" differently for > sealed classes? > > -Archie > > -- > Archie L. Cobbs > > > -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jan 17 15:51:08 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 17 Jan 2023 10:51:08 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <2cfe9abb-a472-0e4d-7688-52da0960297f@oracle.com> Message-ID: <164aa126-61ad-947a-1900-b3f40c0f1af0@oracle.com> With the relaxation you suggest, it seems like abstract base classes that permit this-escape would not be flagged if they are package-private, even if the subclasses are themselves public? I think what we're really appealing to is that the base class offers the _potential_ for this-escape, but some subclasses may decline the opportunity to exploit it, and we have some combinations of classes (abstract package-private base + final public subclass, sealed base + final subclass, etc) where we could do a more global analysis and say "this nest of classes is OK."? But that feels like we're making the analysis more complicated, rather than less?? Or am I missing the question? On 1/16/2023 7:10 PM, Archie Cobbs wrote: > Hmm.. I think we can do something pretty close to what @mcimadamore is > proposing in a way that doesn't care how the compilation is performed. > > The requirement is to be able to look at some class X being compiled > and decide whether any subclasses of X could exist outside of its > "maintenance domain". > > Currently, we have maintenance domain = the compilation unit (i.e., > the file X.java). In this case we ask: Is X not final, not sealed (or, > sealed but permitting some class defined outside of X.java), and does > X have a non-private constructor? > > In the definition that @mcimadamore is proposing, we could ask: Is X > public, not final, not sealed, and does X have a non-private constructor? > > Ideally we'd also ask "Is X's package exported by its module, if any?" > but now you're making assumptions about how the code is being > compiled. But even without that, the above criteria should get you > pretty close I would guess. > > The tangible benefit here is exemplified by the reduction in JDK > warnings from 2093 to 1334 (36%) when you use the tighter criteria. > > I'm thinking since this is a new warning, we should err on the side of > less aggressiveness, but then we can dial it up over time if needed. > Kind of like how GCC's -Wcast-qual has gotten more and more picky over > the years (it seems). > > -Archie > > On Mon, Jan 16, 2023 at 12:45 PM Brian Goetz > wrote: > > This is an interesting one.? The design of sealed classes > deliberately took the unit of maintenance into account: in the > unnamed module, they must be the same package, and in a named > module, they must be in the same module.? I am not sure if we > require that they always be co-compiled; if we already do, then > having the analysis cross the boundary makes sense, but if we > permit a sealed nest to be compiled separately, then it might be > weird to only do the this-escape analysis if they happen to be > being co-compiled? > > On 1/16/2023 1:02 PM, Archie Cobbs wrote: >> Regarding 'this' escape, folks may have already seen the blizzard >> of PR comments but I thought I'd pull out this one >> >> from @mcimadamore as particularly interesting from a design >> perspective: >> >> To be fair, this is what my brain was reading when you talked >> about "compilation unit" - but then saw that the code was >> doing it differently. You see, for "sealed" classes we have a >> notion of "maintenance domain". E.g. the classes in a >> |permits| clause of a |sealed| declaration must belong to the >> same module (if available) or same package (if no module is >> available). That's how you get the exhaustiveness analysis >> and all the goodies, by essentially making a close-world >> assumption on the classes that are passed to javac for a >> given compilation task. I think it would make a lot of sense >> to apply these very same boundaries to the escape-this >> analysis (and, in fact, when looking at warnings coming out >> of the JDK, I often found false positives that were caused by >> this). >> >> >> Any thoughts? Should we define the "boundary of concern" >> differently for sealed classes? >> >> -Archie >> >> -- >> Archie L. Cobbs > > > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Tue Jan 17 22:49:17 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 17 Jan 2023 16:49:17 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <164aa126-61ad-947a-1900-b3f40c0f1af0@oracle.com> References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <2cfe9abb-a472-0e4d-7688-52da0960297f@oracle.com> <164aa126-61ad-947a-1900-b3f40c0f1af0@oracle.com> Message-ID: On Tue, Jan 17, 2023 at 9:51 AM Brian Goetz wrote: > With the relaxation you suggest, it seems like abstract base classes that > permit this-escape would not be flagged if they are package-private, even > if the subclasses are themselves public? > Yes, we would effectively be widening the "maintenance boundary" from the compilation unit to the module, but we would not simultaneously be widening the code that we analyze from the compilation unit to the module. So that opens up some new indirect "holes" like your example. The hope however is that these new holes, which represent potential false negatives, are rare and "module-specific" enough that the trade-off for the reduced false positives is worth it. This is all just a SWAG at what the right thing to do is before we really know how it's going to turn out, and therefore trying to be conservative. At the risk of redundancy, I'll requote this comment from the PR: So far we've stuck to the requirement that whatever analysis we are doing > is done on a a per-file basis, one at a time, so analyzing possible class + > subclass combinations is currently limited to what's available in a single > file. > > Now this is not an inviolate requirement, and removing it would certainly > enable the analysis to rule out more false positives (as with your > example), but it's not something we've really considered doing yet, mainly > because of item 2 below. > > In the big picture, it seems like our goals are roughly: > > 1. Be able to detect a high % of the "truly threatening" leaks that > are out there (minimize false negatives) > 2. Keep the implementation relative simple and minimize compiler > performance impact > 3. Try to avoid having so many false positives that developers are > turned off or annoyed > > I think we're pretty good on item 1, although this one somewhat of a > speculative judgement call. > > For item 2 we're in the right ballpark I think... (others may disagree). > > For item 3, this is where there is still some worry and uncertainty. It's > not just about what kind of leaks/bugs are out there, it's also that it's > hard to predict how humans will react. > > So starting with a less aggressive posture, allowing for getting more so > over time, is a the more conservative option. > > The simplest way to do that is to widen the "maintenance boundary" as > mentioned. Now this could impact item 1 but at least any new false > negatives would necessarily be contained within a single package/module. > > To restate: we can always get more aggressive if that turns out to be > warranted. But if you start out too aggressive and the world barfs on it > and just turns it off, you've probably missed your chance forever. > -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From numeralnathan at gmail.com Wed Jan 18 02:00:53 2023 From: numeralnathan at gmail.com (Nathan Reynolds) Date: Tue, 17 Jan 2023 18:00:53 -0800 Subject: Loosening requirements for super() invocation In-Reply-To: References: <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> Message-ID: > To me it seems like an escaping this-reference is safe if the following condition is fulfilled: One can make sure that the this-reference is only stored by the method to which it is passed as argument, it is not used in any other way before the constructor has completed. The method or class has to be final. Otherwise, a deriving class can override and now "this" escapes. On Tue, Jan 17, 2023 at 5:55 PM Jens Lidestr?m wrote: > On 2022-12-30 17:48, Brian Goetz wrote: > > One thing that makes me a little uncomfortable is that @SW usually is > used to say ?the compiler can?t prove this is safe, but I am asserting it > is.? But this is different; the compiler has discovered the class is > unsafe, > > Is an escaping this-reference really always an unacceptable problem? > > To me it seems like an escaping this-reference is safe if the following > condition is fulfilled: One can make sure that the this-reference is only > stored by the method to which it is passed as argument, it is not used in > any other way before the constructor has completed. > > Looking at the diff in Archie's branch [1], it seems like most cases are > not problematic. > > [1]: > https://github.com/openjdk/jdk/compare/master...archiecobbs:jdk:ThisEscape > > In most cases in the diff the this-reference escapes to be able to do the > following: > > * Set up a circular relationship with another object. > * Register a Cleaner. > * Register a listener. > > Sometimes an object might not be considered to be properly constructed > without doing such things. It seems useful to be able to rely on the > constructor to complete them. > > Regards, > Jens Lidestr?m > > On 2022-12-30 17:48, Brian Goetz wrote: > > Nice. > > > > One thing that makes me a little uncomfortable is that @SW usually is > used to say ?the compiler can?t prove this is safe, but I am asserting it > is.? But this is different; the compiler has discovered the class is > unsafe, and @SW is saying ?I know, I know, stop telling me.? So I think > there?s an additional documentation opportunity here where, for the classes > we had to annotate with @SW, we include an additional @apiNote of the form > ?This class behaves badly, oops?, with a link to a common doc page > explaining the problem. (While we don?t have to do this necessarily > immediately, the chance of it falling on the floor if we don?t are > higher.). Basically, what you?ve identified is that there are a number of > classes in the JDK which fail to follow best practices with regard to > self-use from constructors. We can?t turn back the clock, but we can mark > these as ?don?t code like my brother?, so people see these patterns of > coding and realize they are not to be emulated. > > > > I also see in the code that there are two separate categories, > LeakingThisInConstructor and this-escape; what?s the difference? > > > > > > > >> On Dec 29, 2022, at 11:10 PM, Archie Cobbs > wrote: > >> > >> On Wed, Dec 28, 2022 at 4:31 PM Archie Cobbs > wrote: > >> > >> So fortunately it looks feasible to address these with > @SuppressWarnings("this-escape") annotations. > >> > >> Adding them is probably a good thing in its own right, because they > would serve as new "Heads up for possible 'this' escape" markers in the > code where there were none before, especially because this gotcha can be > pretty hard to spot. > >> > >> I'll work on refining the 'this' escape patch to use > @SuppressWarnings instead of build flags, and then update this thread when > that's done. > >> > >> > >> OK I have a draft of this. It's still a "draft" because I don't have > the ability to build locally for every platform, so I'm having trouble > provoking all the warnings from Java code that is platform-specific. And > the automated github builds take a long time and then only report one more > new warning, making for an impossibly slow feedback loop (if anyone is > interested in helping out, that would be awesome and it's very easy). > >> > >> In any case, the good news is that fewer @SupppressWarnings annotations > than I thought are required. In part this is because there were some > redundant warnings being generated, which is now fixed. > >> > >> Here are the updated stats. These numbers are promisingly low. > >> > >> The first column is the number of @SupppressWarnings annotations added > to eliminate all of the new 'this' escape warnings I'm able to provoke. > >> > >> #SUPPRESS #FILES MODULE > >> 47 3077 java.base > >> 0 128 java.compiler > >> 0 18 java.datatransfer > >> 86 2899 java.desktop > >> 0 10 java.instrument > >> 0 23 java.logging > >> 4 330 java.management > >> 0 16 java.management.rmi > >> 5 199 java.naming > >> 15 142 java.net.http > >> 0 20 java.prefs > >> 4 106 java.rmi > >> 0 15 java.scripting > >> 0 1 java.se < > https://urldefense.com/v3/__http://java.se__;!!ACWV5N9M2RV99hQ!L6fbZinPZagPgDKlgLerhi4QrI3gEtnjcVISBKwwhyNWx6vQLuwL2nKnjRMGg4yMeBEbWn6k5OGYUlLj5kvW3Ws$ > > > >> 7 216 java.security.jgss > >> 0 30 java.security.sasl > >> 0 23 java.smartcardio > >> 1 77 java.sql > >> 0 56 java.sql.rowset > >> 0 5 java.transaction.xa > >> 39 1848 java.xml > >> 32 271 java.xml.crypto > >> 3 20 jdk.accessibility > >> 0 21 jdk.attach > >> 0 18 jdk.charsets > >> 53 333 jdk.compiler > >> 1 76 jdk.crypto.cryptoki > >> 0 35 jdk.crypto.ec < > https://urldefense.com/v3/__http://jdk.crypto.ec__;!!ACWV5N9M2RV99hQ!L6fbZinPZagPgDKlgLerhi4QrI3gEtnjcVISBKwwhyNWx6vQLuwL2nKnjRMGg4yMeBEbWn6k5OGYUlLjMLnBEws$ > > > >> 0 11 jdk.crypto.mscapi > >> 4 68 jdk.dynalink > >> 0 3 jdk.editpad > >> 10 942 jdk.hotspot.agent > >> 3 56 jdk.httpserver > >> 0 5 jdk.incubator.concurrent > >> 0 50 jdk.incubator.vector > >> 0 3 jdk.internal.ed > >> 1 61 jdk.internal.jvmstat > >> 1 113 jdk.internal.le > >> 1 52 jdk.internal.opt > >> 5 209 jdk.internal.vm.ci < > https://urldefense.com/v3/__http://jdk.internal.vm.ci__;!!ACWV5N9M2RV99hQ!L6fbZinPZagPgDKlgLerhi4QrI3gEtnjcVISBKwwhyNWx6vQLuwL2nKnjRMGg4yMeBEbWn6k5OGYUlLjlAiOBII$ > > > >> 0 1 jdk.internal.vm.compiler > >> 0 1 jdk.internal.vm.compiler.management > >> 0 18 jdk.jartool > >> 5 228 jdk.javadoc > >> 0 41 jdk.jcmd > >> 18 64 jdk.jconsole > >> 10 124 jdk.jdeps > >> 25 254 jdk.jdi > >> 0 1 jdk.jdwp.agent > >> 0 263 jdk.jfr > >> 0 77 jdk.jlink > >> 1 80 jdk.jpackage > >> 6 88 jdk.jshell > >> 0 4 jdk.jsobject > >> 1 11 jdk.jstatd > >> 0 281 jdk.localedata > >> 1 25 jdk.management > >> 0 19 jdk.management.agent > >> 0 15 jdk.management.jfr > >> 0 16 jdk.naming.dns > >> 0 8 jdk.naming.rmi > >> 0 11 jdk.net < > https://urldefense.com/v3/__http://jdk.net__;!!ACWV5N9M2RV99hQ!L6fbZinPZagPgDKlgLerhi4QrI3gEtnjcVISBKwwhyNWx6vQLuwL2nKnjRMGg4yMeBEbWn6k5OGYUlLjKWHeJYA$ > > > >> 0 2 jdk.nio.mapmode > >> 0 11 jdk.random > >> 0 37 jdk.sctp > >> 0 30 jdk.security.auth > >> 0 16 jdk.security.jgss > >> 0 9 jdk.unsupported > >> 0 8 jdk.unsupported.desktop > >> 0 94 jdk.xml.dom > >> 1 14 jdk.zipfs > >> > >> Code available here < > https://urldefense.com/v3/__https://github.com/archiecobbs/jdk/tree/ThisEscape__;!!ACWV5N9M2RV99hQ!L6fbZinPZagPgDKlgLerhi4QrI3gEtnjcVISBKwwhyNWx6vQLuwL2nKnjRMGg4yMeBEbWn6k5OGYUlLjPRWM0ZM$ > >. > >> > >> -Archie > >> > >> -- > >> Archie L. Cobbs > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 18 02:01:41 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 17 Jan 2023 21:01:41 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> Message-ID: <2e340780-7ef6-6c0c-c818-d48b72a8cc07@oracle.com> On 12/30/2022 4:37 PM, Jens Lidestr?m wrote: > On 2022-12-30 17:48, Brian Goetz wrote: >> One thing that makes me a little uncomfortable is that @SW usually is >> used to say ?the compiler can?t prove this is safe, but I am >> asserting it is.?? But this is different; the compiler has discovered >> the class is unsafe, > > Is an escaping this-reference really always an unacceptable problem? > > To me it seems like an escaping this-reference is safe if the > following condition is fulfilled:? One can make sure that the > this-reference is only stored by the method to which it is passed as > argument, it is not used in any other way before the constructor has > completed. This is a popular misconception.? An escaping this also voids the final field visibility guarantees (see JLS 17.5). (And, even in the absence of these considerations, errors involving escape (such as calling overridable instance methods from constructors) are difficult to reason about.) > Looking at the diff in Archie's branch [1], it seems like most cases > are not problematic. > > [1]: > https://github.com/openjdk/jdk/compare/master...archiecobbs:jdk:ThisEscape > > In most cases in the diff the this-reference escapes to be able to do > the following: > > * Set up a circular relationship with another object. > * Register a Cleaner. > * Register a listener. While we didn't really understand this in 1995 when a lot of such code was being written, the correct response in these cases is usually to use a factory and a private constructor.? (Registering a listener in this way for non-final classes leaves you open to subtle timing bugs.)? Basically, these behaviors don't mix well with extension. > Sometimes an object might not be considered to be properly constructed > without doing such things. It seems useful to be able to rely on the > constructor to complete them. > > Regards, > Jens Lidestr?m > > On 2022-12-30 17:48, Brian Goetz wrote: >> Nice. >> >> One thing that makes me a little uncomfortable is that @SW usually is >> used to say ?the compiler can?t prove this is safe, but I am >> asserting it is.? ?But this is different; the compiler has discovered >> the class is unsafe, and @SW is saying ?I know, I know, stop telling >> me.? ?So I think there?s an additional documentation opportunity here >> where, for the classes we had to annotate with @SW, we include an >> additional @apiNote of the form ?This class behaves badly, oops?, >> with a link to a common doc page explaining the problem. ?(While we >> don?t have to do this necessarily immediately, the chance of it >> falling on the floor if we don?t are higher.). Basically, what you?ve >> identified is that there are a ?number of classes in the JDK which >> fail to follow best practices with regard to self-use from >> constructors. ?We can?t turn back the clock, but we can mark these as >> ?don?t code like my brother?, so people see these patterns of coding >> and realize they are not to be emulated. >> >> I also see in the code that there are two separate categories, >> LeakingThisInConstructor and this-escape; what?s the difference? >> >> >> >>> On Dec 29, 2022, at 11:10 PM, Archie Cobbs >> > wrote: >>> >>> On Wed, Dec 28, 2022 at 4:31 PM Archie Cobbs >> > wrote: >>> >>> ??? So fortunately it looks feasible to address these with >>> @SuppressWarnings("this-escape") annotations. >>> >>> ??? Adding them is probably a good thing in its own right, because >>> they would serve as new "Heads up for possible 'this' escape" >>> markers in the code where there were none before, especially because >>> this gotcha can be pretty hard to spot. >>> >>> ??? I'll work on refining the 'this' escape patch to use >>> @SuppressWarnings instead of build flags, and then update this >>> thread when that's done. >>> >>> >>> OK I have a draft of this. It's still a "draft" because I don't have >>> the ability to build locally for every platform, so I'm having >>> trouble provoking all the warnings from Java code that is >>> platform-specific. And the automated github builds take a long time >>> and then only report one more new warning, making for an impossibly >>> slow feedback loop (if anyone is interested in helping out, that >>> would be awesome and it's very easy). >>> >>> In any case, the good news is that fewer @SupppressWarnings >>> annotations than I thought are required. In part this is because >>> there were some redundant warnings being generated, which is now fixed. >>> >>> Here are the updated stats. These numbers are promisingly low. >>> >>> The first column is the number of @SupppressWarnings annotations >>> added to eliminate all of the new 'this' escape warnings I'm able to >>> provoke. >>> >>> ?#SUPPRESS ? ?#FILES MODULE >>> ? ? ? ? 47 ? ? ?3077 java.base >>> ? ? ? ? ?0 ? ? ? 128 java.compiler >>> ? ? ? ? ?0 ? ? ? ?18 java.datatransfer >>> ? ? ? ? 86 ? ? ?2899 java.desktop >>> ? ? ? ? ?0 ? ? ? ?10 java.instrument >>> ? ? ? ? ?0 ? ? ? ?23 java.logging >>> ? ? ? ? ?4 ? ? ? 330 java.management >>> ? ? ? ? ?0 ? ? ? ?16 java.management.rmi >>> ? ? ? ? ?5 ? ? ? 199 java.naming >>> ? ? ? ? 15 ? ? ? 142 java.net.http >>> ? ? ? ? ?0 ? ? ? ?20 java.prefs >>> ? ? ? ? ?4 ? ? ? 106 java.rmi >>> ? ? ? ? ?0 ? ? ? ?15 java.scripting >>> ? ? ? ? ?0 ? ? ? ? 1 java.se >>> >>> ? ? ? ? ?7 ? ? ? 216 java.security.jgss >>> ? ? ? ? ?0 ? ? ? ?30 java.security.sasl >>> ? ? ? ? ?0 ? ? ? ?23 java.smartcardio >>> ? ? ? ? ?1 ? ? ? ?77 java.sql >>> ? ? ? ? ?0 ? ? ? ?56 java.sql.rowset >>> ? ? ? ? ?0 ? ? ? ? 5 java.transaction.xa >>> ? ? ? ? 39 ? ? ?1848 java.xml >>> ? ? ? ? 32 ? ? ? 271 java.xml.crypto >>> ? ? ? ? ?3 ? ? ? ?20 jdk.accessibility >>> ? ? ? ? ?0 ? ? ? ?21 jdk.attach >>> ? ? ? ? ?0 ? ? ? ?18 jdk.charsets >>> ? ? ? ? 53 ? ? ? 333 jdk.compiler >>> ? ? ? ? ?1 ? ? ? ?76 jdk.crypto.cryptoki >>> ? ? ? ? ?0 ? ? ? ?35 jdk.crypto.ec >>> >>> ? ? ? ? ?0 ? ? ? ?11 jdk.crypto.mscapi >>> ? ? ? ? ?4 ? ? ? ?68 jdk.dynalink >>> ? ? ? ? ?0 ? ? ? ? 3 jdk.editpad >>> ? ? ? ? 10 ? ? ? 942 jdk.hotspot.agent >>> ? ? ? ? ?3 ? ? ? ?56 jdk.httpserver >>> ? ? ? ? ?0 ? ? ? ? 5 jdk.incubator.concurrent >>> ? ? ? ? ?0 ? ? ? ?50 jdk.incubator.vector >>> ? ? ? ? ?0 ? ? ? ? 3 jdk.internal.ed >>> ? ? ? ? ?1 ? ? ? ?61 jdk.internal.jvmstat >>> ? ? ? ? ?1 ? ? ? 113 jdk.internal.le >>> ? ? ? ? ?1 ? ? ? ?52 jdk.internal.opt >>> ? ? ? ? ?5 ? ? ? 209 jdk.internal.vm.ci >>> >>> ? ? ? ? ?0 ? ? ? ? 1 jdk.internal.vm.compiler >>> ? ? ? ? ?0 ? ? ? ? 1 jdk.internal.vm.compiler.management >>> ? ? ? ? ?0 ? ? ? ?18 jdk.jartool >>> ? ? ? ? ?5 ? ? ? 228 jdk.javadoc >>> ? ? ? ? ?0 ? ? ? ?41 jdk.jcmd >>> ? ? ? ? 18 ? ? ? ?64 jdk.jconsole >>> ? ? ? ? 10 ? ? ? 124 jdk.jdeps >>> ? ? ? ? 25 ? ? ? 254 jdk.jdi >>> ? ? ? ? ?0 ? ? ? ? 1 jdk.jdwp.agent >>> ? ? ? ? ?0 ? ? ? 263 jdk.jfr >>> ? ? ? ? ?0 ? ? ? ?77 jdk.jlink >>> ? ? ? ? ?1 ? ? ? ?80 jdk.jpackage >>> ? ? ? ? ?6 ? ? ? ?88 jdk.jshell >>> ? ? ? ? ?0 ? ? ? ? 4 jdk.jsobject >>> ? ? ? ? ?1 ? ? ? ?11 jdk.jstatd >>> ? ? ? ? ?0 ? ? ? 281 jdk.localedata >>> ? ? ? ? ?1 ? ? ? ?25 jdk.management >>> ? ? ? ? ?0 ? ? ? ?19 jdk.management.agent >>> ? ? ? ? ?0 ? ? ? ?15 jdk.management.jfr >>> ? ? ? ? ?0 ? ? ? ?16 jdk.naming.dns >>> ? ? ? ? ?0 ? ? ? ? 8 jdk.naming.rmi >>> ? ? ? ? ?0 ? ? ? ?11 jdk.net >>> >>> ? ? ? ? ?0 ? ? ? ? 2 jdk.nio.mapmode >>> ? ? ? ? ?0 ? ? ? ?11 jdk.random >>> ? ? ? ? ?0 ? ? ? ?37 jdk.sctp >>> ? ? ? ? ?0 ? ? ? ?30 jdk.security.auth >>> ? ? ? ? ?0 ? ? ? ?16 jdk.security.jgss >>> ? ? ? ? ?0 ? ? ? ? 9 jdk.unsupported >>> ? ? ? ? ?0 ? ? ? ? 8 jdk.unsupported.desktop >>> ? ? ? ? ?0 ? ? ? ?94 jdk.xml.dom >>> ? ? ? ? ?1 ? ? ? ?14 jdk.zipfs >>> >>> Code available here >>> . >>> >>> -Archie >>> >>> -- >>> Archie L. Cobbs >> From archie.cobbs at gmail.com Wed Jan 18 02:46:28 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 17 Jan 2023 20:46:28 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <2e340780-7ef6-6c0c-c818-d48b72a8cc07@oracle.com> References: <75cc216c-12c1-d7bd-37f1-c73d4fc97143@oracle.com> <7242cdba-0b7d-2520-b159-b13f91113c18@oracle.com> <347917af-4663-6fa8-a6b3-6645a3e5f5ce@oracle.com> <2e340780-7ef6-6c0c-c818-d48b72a8cc07@oracle.com> Message-ID: On Tue, Jan 17, 2023 at 8:03 PM Brian Goetz wrote: > > * Register a listener. > > Basically, these behaviors don't mix well with extension. > To demonstrate how subtle the problems can be... What typically happens when you register yourself as a listener? Usually the class that is doing the registering just puts you into a HashSet. No big deal, right? Except adding you to a HashSet means invoking hashCode()... which, if overridden by the subclass, is going to produce the wrong value because it's being calculated from uninitialized fields. So you end up in the wrong hash bucket. Hilarity (or worse) ensues... -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Wed Jan 18 18:00:52 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Wed, 18 Jan 2023 18:00:52 +0000 Subject: CFV: New amber Committer: Adam Sotona Message-ID: I hereby nominate Adam Sotona [asotona] as a committer in the amber Project. Adam Sotona[1] is a member of Oracle's JDK LangTools team and a committer of the jdk project; working on javac, javap, jshell, new classfile[2] and related API and tools. He has made about 40 changes [3][4] to the OpenJDK repository. Votes are due by 20:00 UTC February 1, 2023. Only current committers and reviewers of the amber Project [5] are eligible to vote on this nomination. Votes must be cast in the open by replying to this mailing list. For Lazy Consensus voting instructions, see [6]. Jim Laskey [1] https://openjdk.org/census#asotona [2] https://github.com/openjdk/jdk/pull/10982 [3] https://github.com/openjdk/jdk/search?q=author-name%3A%22Sotona%22&type=commits [4] git log --author="Adam Sotona" --format='%h %s' [5] https://openjdk.org/census#amber [6] https://openjdk.org/groups/#member-vote -------------- next part -------------- An HTML attachment was scrubbed... URL: From james.laskey at oracle.com Wed Jan 18 18:12:26 2023 From: james.laskey at oracle.com (Jim Laskey) Date: Wed, 18 Jan 2023 18:12:26 +0000 Subject: CFV: New amber Committer: Adam Sotona In-Reply-To: References: Message-ID: <23DC64B7-CB7E-4733-9C95-9229BA86B323@oracle.com> Vote: Yes On Jan 18, 2023, at 2:00 PM, Jim Laskey wrote: I hereby nominate Adam Sotona [asotona] as a committer in the amber Project. Adam Sotona[1] is a member of Oracle's JDK LangTools team and a committer of the jdk project; working on javac, javap, jshell, new classfile[2] and related API and tools. He has made about 40 changes [3][4] to the OpenJDK repository. Votes are due by 20:00 UTC February 1, 2023. Only current committers and reviewers of the amber Project [5] are eligible to vote on this nomination. Votes must be cast in the open by replying to this mailing list. For Lazy Consensus voting instructions, see [6]. Jim Laskey [1] https://openjdk.org/census#asotona [2] https://github.com/openjdk/jdk/pull/10982 [3] https://github.com/openjdk/jdk/search?q=author-name%3A%22Sotona%22&type=commits [4] git log --author="Adam Sotona" --format='%h %s' [5] https://openjdk.org/census#amber [6] https://openjdk.org/groups/#member-vote -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 18 18:12:58 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 18 Jan 2023 13:12:58 -0500 Subject: CFV: New amber Committer: Adam Sotona In-Reply-To: References: Message-ID: <3ed40d4d-94f1-2f1d-4a66-486283c77f94@oracle.com> Vote: yes On 1/18/2023 1:00 PM, Jim Laskey wrote: > I hereby nominate Adam Sotona [asotona] as a?committer?in the amber > Project. > > Adam Sotona[1]is a member of Oracle's JDK LangTools team and a > committer of the jdk project; working on javac, javap, jshell, new > classfile[2]and related APIand tools. > > He has made about 40?changes [3][4] to the OpenJDK repository. > > Votes are due by?20:00 UTC February 1, 2023. > > Only current?committers and reviewers of the?amber?Project?[5] are > eligible to vote on this nomination. > Votes must be cast in the open by replying to this mailing list. > > For Lazy Consensus voting instructions, see [6]. > > Jim Laskey > > [1]https://openjdk.org/census#asotona > [2]https://github.com/openjdk/jdk/pull/10982 > > [3]https://github.com/openjdk/jdk/search?q=author-name%3A%22Sotona%22&type=commits > > > [4] git log --author="AdamSotona" --format='%h %s' > > [5] https://openjdk.org/census#a mber > [6] https://openjdk.org/groups/#member-vote -------------- next part -------------- An HTML attachment was scrubbed... URL: From vicente.romero at oracle.com Wed Jan 18 19:11:09 2023 From: vicente.romero at oracle.com (Vicente Romero) Date: Wed, 18 Jan 2023 14:11:09 -0500 Subject: CFV: New amber Committer: Adam Sotona In-Reply-To: References: Message-ID: <07c02261-245d-0cd8-a530-63be4485b9de@oracle.com> vote: yes On 1/18/23 13:00, Jim Laskey wrote: > I hereby nominate Adam Sotona [asotona] as a?committer?in the amber > Project. > > Adam Sotona[1]is a member of Oracle's JDK LangTools team and a > committer of the jdk project; working on javac, javap, jshell, new > classfile[2]and related APIand tools. > > He has made about 40?changes [3][4] to the OpenJDK repository. > > Votes are due by?20:00 UTC February 1, 2023. > > Only current?committers and reviewers of the?amber?Project?[5] are > eligible to vote on this nomination. > Votes must be cast in the open by replying to this mailing list. > > For Lazy Consensus voting instructions, see [6]. > > Jim Laskey > > [1]https://openjdk.org/census#asotona > [2]https://github.com/openjdk/jdk/pull/10982 > > [3]https://github.com/openjdk/jdk/search?q=author-name%3A%22Sotona%22&type=commits > > > [4] git log --author="AdamSotona" --format='%h %s' > > [5] https://openjdk.org/census#a mber > [6] https://openjdk.org/groups/#member-vote -------------- next part -------------- An HTML attachment was scrubbed... URL: From jan.lahoda at oracle.com Thu Jan 19 09:33:42 2023 From: jan.lahoda at oracle.com (Jan Lahoda) Date: Thu, 19 Jan 2023 10:33:42 +0100 Subject: CFV: New amber Committer: Adam Sotona In-Reply-To: References: Message-ID: <9bcd618f-7769-0ea9-7429-600b596f00c5@oracle.com> Vote: yes On 18. 01. 23 19:00, Jim Laskey wrote: > I hereby nominate Adam Sotona [asotona] as a?committer?in the amber > Project. > > Adam Sotona[1]is a member of Oracle's JDK LangTools team and a > committer of the jdk project; working on javac, javap, jshell, new > classfile[2]and related APIand tools. > > He has made about 40?changes [3][4] to the OpenJDK repository. > > Votes are due by?20:00 UTC February 1, 2023. > > Only current?committers and reviewers of the?amber?Project?[5] are > eligible to vote on this nomination. > Votes must be cast in the open by replying to this mailing list. > > For Lazy Consensus voting instructions, see [6]. > > Jim Laskey > > [1]https://openjdk.org/census#asotona > [2]https://github.com/openjdk/jdk/pull/10982 > > [3]https://github.com/openjdk/jdk/search?q=author-name%3A%22Sotona%22&type=commits > > > [4] git log --author="AdamSotona" --format='%h %s' > > [5] https://openjdk.org/census#a mber > [6] https://openjdk.org/groups/#member-vote -------------- next part -------------- An HTML attachment was scrubbed... URL: From gavin.bierman at oracle.com Thu Jan 19 12:29:06 2023 From: gavin.bierman at oracle.com (Gavin Bierman) Date: Thu, 19 Jan 2023 12:29:06 +0000 Subject: CFV: New amber Committer: Adam Sotona In-Reply-To: References: Message-ID: Vote: yes From archie.cobbs at gmail.com Fri Jan 20 17:37:10 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Fri, 20 Jan 2023 11:37:10 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: On Wed, Jan 11, 2023 at 10:27 AM Vicente Romero wrote: > > For the code before super() work (JDK-8194743 > ), is it OK to file a PR > before there is a JEP? > > > it could be done either way but I think that going for the JEP first is > usually a better approach > OK, JEP filed here: https://bugs.openjdk.org/browse/JDK-8300786 Fire away :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From ice1000kotlin at foxmail.com Sat Jan 21 02:23:39 2023 From: ice1000kotlin at foxmail.com (=?utf-8?B?VGVzbGEgWmhhbmc=?=) Date: Fri, 20 Jan 2023 21:23:39 -0500 Subject: About underscores in type arguments / partial type arguments Message-ID: Hi all, Is there any discussion related to partially specified type arguments (which are left for inference)? I just saw that Kotlin 1.7 added support for that. It would be nice if Java can have that too: https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments The demonstration of the feature in the above document is also applicable to Java. Best regards, Tesla -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Sat Jan 21 07:00:54 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Sat, 21 Jan 2023 08:00:54 +0100 (CET) Subject: About underscores in type arguments / partial type arguments In-Reply-To: References: Message-ID: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> > From: "Tesla Ice Zhang" > To: "amber-dev" > Sent: Saturday, January 21, 2023 3:23:39 AM > Subject: About underscores in type arguments / partial type arguments > Hi all, > Is there any discussion related to partially specified type arguments (which are > left for inference)? I just saw that Kotlin 1.7 added support for that. It > would be nice if Java can have that too: > https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments > The demonstration of the feature in the above document is also applicable to > Java. Yes, this has been discussed several times not only in the context of patterns but also in the context of inference in general. For patterns, currently you have to repeat all type arguments Map map = ... switch(map) { case HashMap m -> ... ... we talk about simplify it using case HashMap<> m -> ... but this means also supporting if (map instanceof HashMap<> m) { ... and maybe also supporting if (map instanceof HashMap) { var m = (HashMap<>) map; ... } One issue is that the inference rules are not the same as the usual inference rules, because you want to be able to infer something like HashMap while you do not want to infer new HashMap() in the general context. Currently, we are trying to see if we can avoid to specify the angle brackets all together, so more "case HashMap" than "case HashMap<>". see https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 > Best regards, > Tesla regards, R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Sat Jan 21 10:40:01 2023 From: redio.development at gmail.com (Red IO) Date: Sat, 21 Jan 2023 11:40:01 +0100 Subject: About underscores in type arguments / partial type arguments In-Reply-To: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> References: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> Message-ID: I'm not sure how well this would fit in Java, but rust has long reaching backwards inference. Example: var hashmap = new Hashmap<>(); hashmap.add(5, "Hello"); Where the first use of a type variable here int, String infers the type of the hashmap. This would allow patterns to avoid specifying the type variables they want by inferring them by usage inside the pattern. Great regards RedIODev On Sat, Jan 21, 2023, 08:01 Remi Forax wrote: > > > ------------------------------ > > *From: *"Tesla Ice Zhang" > *To: *"amber-dev" > *Sent: *Saturday, January 21, 2023 3:23:39 AM > *Subject: *About underscores in type arguments / partial type arguments > > Hi all, > Is there any discussion related to partially specified type arguments > (which are left for inference)? I just saw that Kotlin 1.7 added support > for that. It would be nice if Java can have that too: > https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments > > The demonstration of the feature in the above document is also applicable > to Java. > > > Yes, this has been discussed several times not only in the context of > patterns but also in the context of inference in general. > > For patterns, currently you have to repeat all type arguments > > Map map = ... > switch(map) { > case HashMap m -> ... > ... > > we talk about simplify it using > case HashMap<> m -> ... > > but this means also supporting > if (map instanceof HashMap<> m) { ... > > and maybe also supporting > if (map instanceof HashMap) { > var m = (HashMap<>) map; > ... > } > > One issue is that the inference rules are not the same as the usual > inference rules, because you want to be able to infer something like > HashMap while you do not want to infer new HashMap() in the > general context. > > Currently, we are trying to see if we can avoid to specify the angle > brackets all together, so more "case HashMap" than "case HashMap<>". > see > https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 > > > Best regards, > Tesla > > > regards, > R?mi > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Sun Jan 22 00:27:27 2023 From: robbepincket at live.be (Robbe Pincket) Date: Sun, 22 Jan 2023 00:27:27 +0000 Subject: Interesting switch pattern-matching snippets that don't compile but maybe should Message-ID: Hi folks While writing a snippet to show how cool switch pattern matching is, I managed to conceive some of *interesting* snippets, some of which fail to compile with the openjdk early access build 32, but I don't see why they aren't considered valid according to the spec. Let's start with a normal working snippet ``` sealed interface Uber permits Base, Relieve {} sealed interface Base extends Uber permits Foo, Bar, Other{} record Foo() implements Base{} record Bar() implements Base{} record Other() implements Uber{} record Relieve() implements Uber {} class Test { static Uber foo() { return null; } static Base bar() { return null; } static String test1a(){ return switch (bar()){ case null -> "Hi"; case Other o -> "Hello"; }; } static String test1b(){ return switch (foo()){ case null -> "Hi"; case Relieve r -> "Hey"; case Other o -> "Hello"; }; } static String test2(){ return switch (bar()){ case Other o -> "Hello"; }; } static String test3(){ switch (bar()){ case Other o -> { return "Hello"; } } } } ``` This compiles perfectly fine, however, things change when we remove the `other` class. ``` sealed interface Uber permits Base, Relieve {} sealed interface Base extends Uber permits Foo, Bar{} record Foo() implements Base{} record Bar() implements Base{} record Relieve() implements Uber {} ``` Let's look at each method individually ``` static String test1a(){ return switch (bar()){ case null -> "Hi"; }; } ``` This fails with the following error: > the switch expression does not cover all possible input values This might seem obvious to some, given that there is no case for `Base`, but note `test1b`: ``` static String test1b(){ return switch (foo()){ case null -> "Hi"; case Relieve r -> "Hey"; }; } ``` This compiles perfectly fine, even though there is no case that covers `Base` or part of it. As far as I can see, the spec does not give any reason as to why this version of `test1a` shouldn't compile, and disagrees with the reason given by javac. Now for test2. ``` static String test2(){ return switch (bar()){}; } ``` This is against the spec: > It is a compile-time error if a switch expression has no result expressions. test3: ``` static String test3(){ switch (bar()){}; } ``` This one, after a bit more checking is also, illegal according to the spec, but we aren't in the clear yet. The only reason I could find that `test3` was illegal is "14.22. Unreachable Statements". > A switch statement whose switch block is empty [...] can complete normally. This means our methodblock can complete normally which isn't allowed. Note that javac complains again about the switch not covering all input values, which isn't true. We can fix our method however, so it is valid according to the spec. ``` static String test3(){ String s; switch (bar()){}; return s; } ``` Now this might seems crazy, but Chapter 16. Definite Assignment sees the switch differently, and "realizes" that the switch can not complete normally, (read: all variables are considered to be both definite unassigned and definite assigned). As a result we can read from `s` even though there are no assignments. This does not work however, and just adds a second error: > variable s might not have been initialized Greetings Robbe Pincket -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Sun Jan 22 01:03:59 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Sat, 21 Jan 2023 20:03:59 -0500 Subject: Interesting switch pattern-matching snippets that don't compile but maybe should Message-ID: Am I missing something? Your first example does not compile. I pulled down the early access 32 build, and the first example that you said compiles fine, doesn't. Here is the link I downloaded from -- https://download.java.net/java/early_access/jdk20/32/GPL/openjdk-20-ea+32_windows-x64_bin.zip Here is my java --version output. openjdk 20-ea 2023-03-21 OpenJDK Runtime Environment (build 20-ea+32-2328) OpenJDK 64-Bit Server VM (build 20-ea+32-2328, mixed mode, sharing) And here is my javac --version output. javac 20-ea And then here is what happens when I try to compile your first example. --------- PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java:7: error: invalid permits clause sealed interface Base extends Uber permits Foo, Bar, Other{} ^ (subclass Other must extend sealed class) where T is a type-variable: T extends Object declared in record Other PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java:10: error: class is not allowed to extend sealed class: Uber (as it is not listed in its permits clause) record Other() implements Uber{} ^ PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java:25: error: incompatible types: Base cannot be converted to Other case Other o -> "Hello"; ^ PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java:39: error: incompatible types: Base cannot be converted to Other case Other o -> "Hello"; ^ PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java:45: error: incompatible types: Base cannot be converted to Other case Other o -> { ^ Note: PotentialJavaBugs\src\main\java\io\github\davidalayachew\ShouldThisCompile.java uses preview features of Java SE 20. Note: Recompile with -Xlint:preview for details. 5 errors ----------- Please let me know if I am missing something. -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Sun Jan 22 14:00:05 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Sun, 22 Jan 2023 09:00:05 -0500 Subject: About underscores in type arguments / partial type arguments In-Reply-To: References: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> Message-ID: The main choices you get in selecting a type inference scheme are (a) where to gather constraints and (b) when to solve them.? Java chooses, sensible, to do its solving at the level of a single statement or expression, rather than the entire body of a method.? While this might seem like "throwing away useful information", it enables more local reasoning; you don't have to worry about implementation details hundreds of lines away affecting the result of inference.? I think its safe to say we made our choice a long time ago and are still happy with it. (BTW, Rust didn't invent global type inference either; see https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system.) On 1/21/2023 5:40 AM, Red IO wrote: > I'm not sure how well this would fit in Java, but rust has long > reaching backwards inference. Example: > var hashmap = new Hashmap<>(); > hashmap.add(5, "Hello"); > Where the first use of a type variable here int, String infers the > type of the hashmap. > This would allow patterns to avoid specifying the type variables they > want by inferring them by usage inside the pattern. > > Great regards > RedIODev > > On Sat, Jan 21, 2023, 08:01 Remi Forax wrote: > > > > ------------------------------------------------------------------------ > > *From: *"Tesla Ice Zhang" > *To: *"amber-dev" > *Sent: *Saturday, January 21, 2023 3:23:39 AM > *Subject: *About underscores in type arguments / partial type > arguments > > Hi all, > Is there any discussion related to partially specified type > arguments (which are left for inference)? I just saw that > Kotlin 1.7 added support for that. It would be nice if Java > can have that too: > https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments > > The demonstration of the feature in the above document is also > applicable to Java. > > > Yes, this has been discussed several times not only in the context > of patterns but also in the context of inference in general. > > For patterns, currently you have to repeat all type arguments > > ? Map map = ... > ? switch(map) { > ??? case HashMap m -> ... > ??? ... > > we talk about simplify it using > ?? case HashMap<> m -> ... > > but this means also supporting > ? if (map instanceof HashMap<> m) { ... > > and maybe also supporting > ? if (map instanceof HashMap) { > ??? var m = (HashMap<>) map; > ??? ... > ? } > > One issue is that the inference rules are not the same as the > usual inference rules, because you want to be able to infer > something like HashMap while you do not want to infer new > HashMap() in the general context. > > Currently, we are trying to see if we can avoid to specify the > angle brackets all together, so more "case HashMap" than "case > HashMap<>". > see > https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 > > > Best regards, > Tesla > > > regards, > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Sun Jan 22 15:21:10 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Sun, 22 Jan 2023 16:21:10 +0100 (CET) Subject: About underscores in type arguments / partial type arguments In-Reply-To: References: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> Message-ID: <1147865423.3220502.1674400870185.JavaMail.zimbra@u-pem.fr> > From: "Brian Goetz" > To: "Red IO" , "Remi Forax" > Cc: "Tesla Ice Zhang" , "amber-dev" > > Sent: Sunday, January 22, 2023 3:00:05 PM > Subject: Re: About underscores in type arguments / partial type arguments > The main choices you get in selecting a type inference scheme are (a) where to > gather constraints and (b) when to solve them. Java chooses, sensible, to do > its solving at the level of a single statement or expression, rather than the > entire body of a method. While this might seem like "throwing away useful > information", it enables more local reasoning; you don't have to worry about > implementation details hundreds of lines away affecting the result of > inference. I think its safe to say we made our choice a long time ago and are > still happy with it. > (BTW, Rust didn't invent global type inference either; see [ > https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system | > https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system ] .) I don't know Rust well, i've just played with it but as i understand it does not use global inference but more a kind of delayed inference, there is a type (say Unknown) which say that there is no constraint and later when constraints are found, Unknown is replaced by type inferred. I've seen something similar in Haxe (which predates Rust). It works well in Rust because Rust uses a type flow algorithm where the type of a variable change depending on the control flow (like Kotlin or TypeScript). regards, R?mi > On 1/21/2023 5:40 AM, Red IO wrote: >> I'm not sure how well this would fit in Java, but rust has long reaching >> backwards inference. Example: >> var hashmap = new Hashmap<>(); >> hashmap.add(5, "Hello"); >> Where the first use of a type variable here int, String infers the type of the >> hashmap. >> This would allow patterns to avoid specifying the type variables they want by >> inferring them by usage inside the pattern. >> Great regards >> RedIODev >> On Sat, Jan 21, 2023, 08:01 Remi Forax < [ mailto:forax at univ-mlv.fr | >> forax at univ-mlv.fr ] > wrote: >>>> From: "Tesla Ice Zhang" < [ mailto:ice1000kotlin at foxmail.com | >>>> ice1000kotlin at foxmail.com ] > >>>> To: "amber-dev" < [ mailto:amber-dev at openjdk.org | amber-dev at openjdk.org ] > >>>> Sent: Saturday, January 21, 2023 3:23:39 AM >>>> Subject: About underscores in type arguments / partial type arguments >>>> Hi all, >>>> Is there any discussion related to partially specified type arguments (which are >>>> left for inference)? I just saw that Kotlin 1.7 added support for that. It >>>> would be nice if Java can have that too: [ >>>> https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments >>>> | >>>> https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments >>>> ] >>>> The demonstration of the feature in the above document is also applicable to >>>> Java. >>> Yes, this has been discussed several times not only in the context of patterns >>> but also in the context of inference in general. >>> For patterns, currently you have to repeat all type arguments >>> Map map = ... >>> switch(map) { >>> case HashMap m -> ... >>> ... >>> we talk about simplify it using >>> case HashMap<> m -> ... >>> but this means also supporting >>> if (map instanceof HashMap<> m) { ... >>> and maybe also supporting >>> if (map instanceof HashMap) { >>> var m = (HashMap<>) map; >>> ... >>> } >>> One issue is that the inference rules are not the same as the usual inference >>> rules, because you want to be able to infer something like HashMap while >>> you do not want to infer new HashMap() in the general context. >>> Currently, we are trying to see if we can avoid to specify the angle brackets >>> all together, so more "case HashMap" than "case HashMap<>". >>> see [ >>> https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 >>> | >>> https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 >>> ] >>>> Best regards, >>>> Tesla >>> regards, >>> R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Sun Jan 22 16:10:48 2023 From: redio.development at gmail.com (Red IO) Date: Sun, 22 Jan 2023 17:10:48 +0100 Subject: About underscores in type arguments / partial type arguments In-Reply-To: <1147865423.3220502.1674400870185.JavaMail.zimbra@u-pem.fr> References: <33376105.2687011.1674284454069.JavaMail.zimbra@u-pem.fr> <1147865423.3220502.1674400870185.JavaMail.zimbra@u-pem.fr> Message-ID: Yes as my example showed and tesla correctly added rust uses type inference on scope level (not global). But rusts variables never change type if not casted (safe or unsafe) the type and inference system is in fact very strict amd completely different from something like typescript. I agree with Brian that using "backwards inference" would be confusing and or would require every inference to use it what would be confusing too. But as I was reading the examples from remi again and doing some testing of my own there isn't really a need for this in this idea. Since: Object o = new ArrayList(); if (o instanceof ArrayList f) { ... } Where Foo is any type including String. Is always a compilation error since it cannot be solved by static analysis. The only pattern where: if (foo instanceof Bar b) { ... } Is valid is when foo's generic parameters match these from Bar (or include them) and therefore static analysis can typecheck the generic parameters. (not possible at runtime due to type erasure). Therefore we can assume that we know the generic parameters at time of instanceof / case and can safely infer them using <> when we do not want to change the bound of the generic parameters like . I think adding inference to this pattern would be very beneficial to readability and writeability. Great regards RedIODev On Sun, Jan 22, 2023, 16:21 wrote: > > > ------------------------------ > > *From: *"Brian Goetz" > *To: *"Red IO" , "Remi Forax" < > forax at univ-mlv.fr> > *Cc: *"Tesla Ice Zhang" , "amber-dev" < > amber-dev at openjdk.org> > *Sent: *Sunday, January 22, 2023 3:00:05 PM > *Subject: *Re: About underscores in type arguments / partial type > arguments > > The main choices you get in selecting a type inference scheme are (a) > where to gather constraints and (b) when to solve them. Java chooses, > sensible, to do its solving at the level of a single statement or > expression, rather than the entire body of a method. While this might seem > like "throwing away useful information", it enables more local reasoning; > you don't have to worry about implementation details hundreds of lines away > affecting the result of inference. I think its safe to say we made our > choice a long time ago and are still happy with it. > > (BTW, Rust didn't invent global type inference either; see > https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system.) > > > I don't know Rust well, i've just played with it but as i understand it > does not use global inference but more a kind of delayed inference, there > is a type (say Unknown) which say that there is no constraint and later > when constraints are found, Unknown is replaced by type inferred. I've seen > something similar in Haxe (which predates Rust). > It works well in Rust because Rust uses a type flow algorithm where the > type of a variable change depending on the control flow (like Kotlin or > TypeScript). > > regards, > R?mi > > On 1/21/2023 5:40 AM, Red IO wrote: > > I'm not sure how well this would fit in Java, but rust has long reaching > backwards inference. Example: > var hashmap = new Hashmap<>(); > hashmap.add(5, "Hello"); > Where the first use of a type variable here int, String infers the type of > the hashmap. > This would allow patterns to avoid specifying the type variables they want > by inferring them by usage inside the pattern. > > Great regards > RedIODev > > On Sat, Jan 21, 2023, 08:01 Remi Forax wrote: > >> >> >> ------------------------------ >> >> *From: *"Tesla Ice Zhang" >> *To: *"amber-dev" >> *Sent: *Saturday, January 21, 2023 3:23:39 AM >> *Subject: *About underscores in type arguments / partial type arguments >> >> Hi all, >> Is there any discussion related to partially specified type arguments >> (which are left for inference)? I just saw that Kotlin 1.7 added support >> for that. It would be nice if Java can have that too: >> https://kotlinlang.org/docs/whatsnew17.html#underscore-operator-for-type-arguments >> >> The demonstration of the feature in the above document is also applicable >> to Java. >> >> >> Yes, this has been discussed several times not only in the context of >> patterns but also in the context of inference in general. >> >> For patterns, currently you have to repeat all type arguments >> >> Map map = ... >> switch(map) { >> case HashMap m -> ... >> ... >> >> we talk about simplify it using >> case HashMap<> m -> ... >> >> but this means also supporting >> if (map instanceof HashMap<> m) { ... >> >> and maybe also supporting >> if (map instanceof HashMap) { >> var m = (HashMap<>) map; >> ... >> } >> >> One issue is that the inference rules are not the same as the usual >> inference rules, because you want to be able to infer something like >> HashMap while you do not want to infer new HashMap() in the >> general context. >> >> Currently, we are trying to see if we can avoid to specify the angle >> brackets all together, so more "case HashMap" than "case HashMap<>". >> see >> https://cr.openjdk.java.net/~gbierman/jep432%2b433/jep432+433-20221115/specs/patterns-switch-record-patterns-jls.html#jls-18.5.5 >> >> >> Best regards, >> Tesla >> >> >> regards, >> R?mi >> >> > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Sun Jan 22 16:16:34 2023 From: robbepincket at live.be (Robbe Pincket) Date: Sun, 22 Jan 2023 16:16:34 +0000 Subject: Interesting switch pattern-matching snippets that don't compile but maybe should In-Reply-To: References: Message-ID: Sun Jan 22 01:03:59 UTC 2023, David Alayachew: > Am I missing something? Your first example does not compile. My bad, I changed something about the examples during the riting of the email and seemed to have copied something incorrectly. The line defining `Other` should be extending `Base` and not `Uber`: `record Other() implements Base{}` The other errors seemed to be a result of this error. Kind regards Robbe Pincket -------------- next part -------------- An HTML attachment was scrubbed... URL: From davidalayachew at gmail.com Mon Jan 23 02:41:03 2023 From: davidalayachew at gmail.com (David Alayachew) Date: Sun, 22 Jan 2023 21:41:03 -0500 Subject: Interesting switch pattern-matching snippets that don't compile but maybe should In-Reply-To: References: Message-ID: Hello Robbe, Thank you for your response. > My bad, I changed something about > the examples during the writing of > the email and seemed to have copied > something incorrectly. The line > defining `Other` should be extending > `Base` and not `Uber` Ok, thank you for your clarification. Your original example compiles now, just like you said. > The other errors seemed to be a > result of this error. Just to confirm, are you saying that now that you have corrected this error, you are no longer seeing the behaviour you mentioned in your original message? Thank you for reaching out! David Alayachew On Sun, Jan 22, 2023 at 11:16 AM Robbe Pincket wrote: > Sun Jan 22 01:03:59 UTC 2023, David Alayachew: > > > > > Am I missing something? Your first example does not compile. > > > > My bad, I changed something about the examples during the riting of > > the email and seemed to have copied something incorrectly. > > The line defining `Other` should be extending `Base` and not `Uber`: > > > > `record Other() implements Base{}` > > > > The other errors seemed to be a result of this error. > > > > Kind regards > > Robbe Pincket > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jan 23 20:01:23 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 23 Jan 2023 15:01:23 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: > OK, JEP filed here: https://bugs.openjdk.org/browse/JDK-8300786 > Fire away :) Incoming fire.... Overall this is a pretty good job on a first pass!? Some comments, mostly on presentation, but some on substance. > Summary > ------- > > No longer require `super()` and `this()` to appear first in a constructor. Framing it this way is negative, and requires users to understand the restriction that you are loosening.? Instead, a more positive framing is: > Allow statements that do not reference the instance being created to appear before the `this` or `super` call in a constructor. > Goals > ----- > > Change the Java Language Specification and make corresponding changes > to the Java compiler so that: Changing the JLS and implementation are consequences of changing the _language_, so start there.? Also, "don't change the meaning of existing programs" is table stakes, so we don't call that out as a goal. > * `super()` and `this()` no longer must appear as the first statement > in a constructor > * The language preserves existing safety and initialization guarantees > afforded to constructors > * Existing programs continue to compile and function as they did before * Allow statements that do not reference the instance being created to appear before the `this` or `super` constructors calls in a constructor. * Preserve existing safety and initialization guarantees for constructors > Non-Goals > --------- > > __Modifications to the JVM.__ These changes may prompt reconsideration > of the JVM's current restrictions on constructors, however, in order > to avoid unnecessary linkage between JLS and JVM changes, any such > modifications should be proposed in a follow-on JEP. This JEP assumes > no change to the current JVM behavior. I would add a non-goal that we are not necessarily going to make the JLS align with the JVMS here either; the two address different domains and may reasonably differ.? For example, the JVMS allows multiple writes to the same final field, but the language does not. We are not going to change that here, and that's OK. > Motivation > ---------- > > Currently, the Java language requires that invocations of `this()` or > `super()` appear as the first statement in a constructor. You should follow up with the motivation for this requirement, and then can talk about how it doesn't achieve all those goals and that's why we're you're proposing improving it.? The goal was to ensure that the superclass representation is at least in a known state before we start operating on it, but as you'll show, this isn't really enough to prevent us from accessing incompletely initialized instances.? So it was a good try, with good motivation, but we still have a problem with initialization safety, *and* certain idioms are hard to express. I would then lead into the idioms that are hard to express, and the workarounds users are driven to as a result, to show how the cure may be worse than the disease. > However, the Java Virtual Machine actually allows more flexibility: I would defer this section to later; most Java programmers are only vaguely aware of the JVM spec or how it aligns or fails to align with the JLS (or why).? Instead, after providing an example of the hoops we force users to jump through, we can observe that there is a safe alternative (allow computation that doesn't touch `this` except in the trivial case of field writes) and that, yay, the JVM already accepts such bytecode without modifying the JVMS. > There is also a practical motivation, which is that it's often > convenient to be able to do "housekeeping" before invoking `super()` > or `this()`. This is the argument I would lead with: it makes users jump through hoops for no incremental safety. > Here's a somewhat contrived example: Perhaps you should lead with a less contrived example, lest readers think that this whole JEP is about solving contrived problems. (This is not an idle concern!? We get this all the time.)? Or maybe it's not a contrived example -- it seems to me that your BPV constructor is following the "fail fast" imperative outlined in Effective Java.? So maybe not so contrived. But it is useful, in any case, to chracterize _what kind of code_ we might want before this/super.? Which I think comes down to: ?- validating inputs ?- computing complex, possibly-failing inputs into the super constructor, or ?- computing values that will be used _multiple times_ in the super constructor invocation > Another reason is to provide a way to avoid bugs caused by a 'this' > escape in a superclass constructor. A 'this' escape is when a > superclass constructor does something that could cause a subclass > method to be invoked before the superclass constructor returns; in > such cases the subclass method would operate on an incompletely > initialized instance. Yes, this is a nice side effect of "do the work that might fail before you expose `this`."? A good thing to end the motivation on. > Description > ----------- > > ## Language Changes > > The JLS will be modified as follows: > > * Remove the requirement that `super()` or `this()` appear as the > first statement in a constructor > * Add the requirement that, in any constructor with explicit `super()` > and/or `this()` invocations, either `super()` or `this()` must be > invoked exactly once (assuming the constructor returns normally). This > may be specified economically by stating that the compiler treats > superclass initialization like a non-static blank final field. A more precise way to state this is that: ?- The `this` reference is considered DU on entry to the constructor; ?- The `this` reference is considered DA after a this/super call; ?- At a this/super call, `this` must be DU; ?- If no this/super call is present in the constructor body, it is treated as if that the first line of the constructor is `super()`; Plus some wording about the use of `this` implicitly when it is DU. > * Add the requirement that `super()` and `this()` may not appear > within any `try { }` block if `this` is DA/U on entry to a try block, it must be DA/U on exit from that try block > * Specify that non-static field initializers and initialization blocks > are executed immediately after `super()` invocation, wherever it occurs > > Note: there is no change to the implicit addition of `super()` at the > beginning of any constructor having no explicit `super()` or `this()` > invocation. > > ### `try { }` Blocks > > The restriction that `super()` and `this()` may not appear inside a > `try { }` block comes from the JVM itself, and is due to how StackMaps > are represented. The logic is that when a superclass constructor > throws an exception, the new instance on the stack is neither fully > uninitialized nor fully initialized, so it should be considered > unusable, and therefore such a constructor must never return. However, > the JVM doesn't allow the bytecode to discard the unusable instance > and throw another exception; instead, it doesn't allow it to exist on > the stack at all. The net effect is that constructors can't catch > exceptions thrown by superclass initialization, even if rethrown. > > ### Initialization Order > > The JLS specifies that field initializers and initialization blocks > execute after superclass initialization via `super()`. So this class: > > ??? class Test1 { > ??????? final int x; > ??????? { > ??????????? x = 123; > ??????? } > ??????? public Test1() { > ??????????? super(); > ??????????? this.x = 456; > ??????? } > ??? } > > generates this error: > > ??? Test1.java:8: error: variable x might already have been assigned > ??????????? this.x = 456; > ??????????????? ^ > > However, now that `super()` can appear anywhere in a constructor, an > assignment in an initializer block can now happen after an earlier > assignment in a constructor. So this class: > > ??? class Test1 { > ??????? final int x; > ??????? { > ??????????? x = 123; > ??????? } > ??????? public Test1() { > ??????????? this.x = 456; > ??????????? super(); > ??????? } > ??? } > > will now generate this error: > > ??? Test1.java:4: error: variable x might already have been assigned > ??????????? x = 123; > ??????????? ^ > > As before, initializers and initialization blocks happen immediately > after superclass initialization, which happens when `super()` is > invoked. But now this can be anywhere in the constructor. > > One might ask why not move initializers and initialization blocks to > the start of every constructor, but that doesn't work. First, they > could have early references (e.g., by invoking an instance method), > and second, the constructor might invoke `this()` and `super()` on > different code branches, so you'd be executing the initialization > twice in the `this()` case. > > ### Records > > Record constructors are subject to more restrictions that normal > constructors. In particular: > > * Canonical record constructors may not contain any explicit `super()` > or `this()` invocation > * Non-canonical record constructors may invoke `this()`, but not `super()` > > These restrictions remain in place, but otherwise record constructors > benefit from these changes. The net change is that non-canonical > record constructors can now invoke `this()` multiple times, as long as > it is invoked exactly once along any code path. I'd like to come back and think about the record constraints some more after we have nailed down the non-record story. > ## Compiler Changes Generally the JEP does not have to outline the compiler changes, as long as the language changes are clearly described.? However, if you see specific risks and concerns, they can be called out in the Risks section.? Most of the rest can move to a "implementation plan" document whose primary consumers will be the current maintainers of the compiler, to help build a shared underestanding of how to proceed. From robbepincket at live.be Mon Jan 23 20:39:02 2023 From: robbepincket at live.be (Robbe Pincket) Date: Mon, 23 Jan 2023 20:39:02 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: Mon Jan 23 20:01:23 UTC 2023, Brian Goetz: >> * Add the requirement that `super()` and `this()` may not appear >> within any `try { }` block > > if `this` is DA/U on entry to a try block, it must be DA/U on exit from that try block Those are only equivalent if there is no return/throw/break/continue/yield inside the try block. ``` // `this` is DU and not DA try { // `this` is DU and not DA if (arg1 > 0){ this(arg2); // `this` is DA and not DU return; // `this` is DA and DU } // `this` is DU and not DA } ``` Kind regards Robbe Pincket -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Mon Jan 23 20:42:44 2023 From: robbepincket at live.be (Robbe Pincket) Date: Mon, 23 Jan 2023 20:42:44 +0000 Subject: Interesting switch pattern-matching snippets that don't compile but maybe should In-Reply-To: References: Message-ID: Mon Jan 23 02:41:03 UTC 2023: David Alayachew: >> The other errors seemed to be a >> result of this error. > > Just to confirm, are you saying that now that you have corrected this error, you are no longer seeing the behaviour you mentioned in your original message? No, I meant the 4 other errors that appeared in the first example due to `Other` implementing the wrong interface. All the other examples are about what happens if `Other` doesn't exist, so they shouldn't have been affected. Kind regards Robbe Pincket -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Jan 23 21:03:55 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 23 Jan 2023 15:03:55 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: On Mon, Jan 23, 2023 at 2:01 PM Brian Goetz wrote: > > > OK, JEP filed here: https://bugs.openjdk.org/browse/JDK-8300786 > > Fire away :) > > Incoming fire.... > (ducks!) Seriously, these are all very helpful comments that I concur with - thanks. I'll work on corresponding updates. > ## Compiler Changes > > Generally the JEP does not have to outline the compiler changes, as long > as the language changes are clearly described. > I put those details in there because they were already written and lying around but am glad to hear they're not needed. It's good to stay out of the weeds if possible. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jan 24 00:42:10 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 23 Jan 2023 19:42:10 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: Yes, substitute "normal completion" for "exit". On 1/23/2023 3:39 PM, Robbe Pincket wrote: > > Mon Jan 23 20:01:23 UTC 2023, Brian Goetz: > > >> * Add the requirement that `super()` and `this()` may not appear > > >> within any `try { }` block > > > > > > if `this` is DA/U on entry to a try block, it must be DA/U on exit from > > that try block > > Those are only equivalent if there is no return/throw/break/continue/yield > > inside the try block. > > ``` > > // `this` is DU and not DA > > try { > > ??? // `this` is DU and not DA > > ??? if (arg1 > 0){ > > ??????? this(arg2); > > ??????? // `this` is DA and not DU > > ??????? return; > > ??????? // `this` is DA and DU > > ??? } > > ??? // `this` is DU and not DA > > } > > ``` > > Kind regards > > Robbe Pincket > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Tue Jan 24 20:11:09 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 24 Jan 2023 14:11:09 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: On Mon, Jan 23, 2023 at 3:03 PM Archie Cobbs wrote: > On Mon, Jan 23, 2023 at 2:01 PM Brian Goetz > wrote: > >> >> > OK, JEP filed here: https://bugs.openjdk.org/browse/JDK-8300786 >> > Fire away :) >> >> Incoming fire.... >> > > Updates applied. Thanks again for the review. > > if `this` is DA/U on entry to a try block, it must be DA/U on exit from >> that try block >> > This made me realize there is another missing requirement: - Upon normal return from a constructor, the `this` reference must be DA Wouldn't that requirement subsume the one about try blocks? What I mean is, the normal dataflow analysis already takes care of try blocks, and what we care about is the DA/DU state when the constructor eventually returns. Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jan 24 20:21:01 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 24 Jan 2023 15:21:01 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> > This made me realize there is another missing requirement: > > * Upon normal return from a constructor, the `this` reference must > be DA > So, I think this is true by definition; on normal return from a super/this/implicit super call, then `this` *is* DA. You can simplify the rule about try blocks to: ?- if `this` is DU on entry to a try block, it must be DU on normal completion of the try block. Can you simplify further, while still preventing `this` calls inside a try block?? I don't think so, since we might want to allow a try block before the super/this call. -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Tue Jan 24 21:24:12 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Tue, 24 Jan 2023 15:24:12 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> Message-ID: On Tue, Jan 24, 2023 at 2:21 PM Brian Goetz wrote: > > This made me realize there is another missing requirement: > > - Upon normal return from a constructor, the `this` reference must be > DA > > > So, I think this is true by definition; on normal return from a > super/this/implicit super call, then `this` *is* DA. > > You can simplify the rule about try blocks to: > > - if `this` is DU on entry to a try block, it must be DU on normal > completion of the try block. > > Can you simplify further, while still preventing `this` calls inside a try > block? I don't think so, since we might want to allow a try block before > the super/this call. > Ok thanks. I admit I'm getting a little out of my league here. Does this sound correct? The JLS will be modified as follows: * Remove the requirement that `super()` or `this()` appear as the first statement in a constructor * Add superclass initialization to the existing constructor dataflow analysis as follows: * The `this` reference is considered DU on entry to the constructor * Before a `this()` or `super()` call, the `this` reference must be DU * After a `this()` or `super()` call, the `this` reference is considered DA * Before normal completion of the constructor, the `this` reference must be DA * If `this` is DU on entry to a `try` block, it must be DU on normal completion of the `try` block * If no explicit `this()` or `super()` appears in a constructor, it is treated as if the first line of the constructor were `super()` * Add the following restrictions on constructors: * No access to `this`, other than assignments to fields, may occur unless `this` is DA * `super()` and `this()` may not appear within any `try { }` block * Clarify that non-static field initializers and initialization blocks are executed immediately after `super()` invocation, wherever it occurs (see "Initialization Order" below) Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jan 24 23:01:04 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 24 Jan 2023 18:01:04 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> Message-ID: <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> The basic design seems sound enough.? Probably time to dig to the next level, which is assessing the spec impact. The places to start are Ch16 (definite assignment) and 8.8.7 (constructor bodies). On 1/24/2023 4:24 PM, Archie Cobbs wrote: > On Tue, Jan 24, 2023 at 2:21 PM Brian Goetz > wrote: > > >> This made me realize there is another missing requirement: >> >> * Upon normal return from a constructor, the `this` reference >> must be DA >> > > So, I think this is true by definition; on normal return from a > super/this/implicit super call, then `this` *is* DA. > > You can simplify the rule about try blocks to: > > ?- if `this` is DU on entry to a try block, it must be DU on > normal completion of the try block. > > Can you simplify further, while still preventing `this` calls > inside a try block?? I don't think so, since we might want to > allow a try block before the super/this call. > > > Ok thanks. I admit I'm getting a little out of my league here. > > Does this sound correct? > > ?The JLS will be modified as follows: > > ?* Remove the requirement that `super()` or `this()` appear as the > first statement in a constructor > ?* Add superclass initialization to the existing constructor dataflow > analysis as follows: > ???? * The `this` reference is considered DU on entry to the constructor > ? ? ?* Before a `this()` or `super()` call, the `this` reference must > be DU > ? ? ?* After a `this()` or `super()` call, the `this` reference is > considered DA > ???? * Before normal completion of the constructor, the `this` > reference must be DA > ???? * If `this` is DU on entry to a `try` block, it must be DU on > normal completion of the `try` block > ? ? ?* If no explicit `this()` or `super()` appears in a constructor, > it is treated as if the first line of the constructor were `super()` > ?* Add the following restrictions on constructors: > ? ? ?* No access to `this`, other than assignments to fields, may > occur unless `this` is DA > ? ? ?* `super()` and `this()` may not appear within any `try { }` block > ?* Clarify that non-static field initializers and initialization > blocks are executed immediately after `super()` invocation, wherever > it occurs (see "Initialization Order" below) > > > Thanks, > ?-Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Tue Jan 24 23:16:45 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Tue, 24 Jan 2023 18:16:45 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> Message-ID: <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Hit "send" a little too soon. The assertion that governs "no use of `this` in a super/this call" is in 8.8.7.1: > An explicit constructor invocation statement introduces a static > context (?8.1.3), > which limits the use of constructs that refer to the current object. > Notably, the > keywords this and super are prohibited in a static context (?15.8.3, > ?15.11.2), > as are unqualified references to instance variables, instance methods, > and type > parameters of lexically enclosing declarations (?6.5.5.1, ?6.5.6.1, > ?15.12.3). This needs to be generalized to speak about the use of `this` throughout the constructor body; basically, that you can never use `this` (explicitly or implicitly) prior to to the super/this call. There are a few ways you could do this: ?- A full-blown treatment of DA/DU for `this`; ?- An extension of the "introduces a static context" used in this section, that covers the entire initial segment of the constructor body up through and including the this/super-call. Similarly, you'll need a way to restate the "if it doesn't start with `this/super`, you get an implicit super" to the more flexible notion being outlined here.? This is tricky because the obvious way to do this is to run DA/DU on the explicit body of the constructor and ask if `this` is DA at all points where the constructor could complete normally, and if not, prepend a super() call and rerun DA/DU.? This moves us from a strictly syntactic rule to one that appeals to a complex analysis. We can simplify this analysis a lot by lowering the target, from one that is based on DA to funneling through a single super/this choke point, where a ctor body with an explicit super/this looks like: ??? statement* ??? super/this call ??? statement* This would rule out constructs like: ??? Foo() { ??????? if (bar) ??????????? this(f(bar)); ??????? else ??????????? this(g(bar), 0); ??? } but is a lot simpler to specify and still offers the "stuff before super" benefit. On 1/24/2023 6:01 PM, Brian Goetz wrote: > The basic design seems sound enough.? Probably time to dig to the next > level, which is assessing the spec impact. > > The places to start are Ch16 (definite assignment) and 8.8.7 > (constructor bodies). > > On 1/24/2023 4:24 PM, Archie Cobbs wrote: >> On Tue, Jan 24, 2023 at 2:21 PM Brian Goetz >> wrote: >> >> >>> This made me realize there is another missing requirement: >>> >>> * Upon normal return from a constructor, the `this` reference >>> must be DA >>> >> >> So, I think this is true by definition; on normal return from a >> super/this/implicit super call, then `this` *is* DA. >> >> You can simplify the rule about try blocks to: >> >> ?- if `this` is DU on entry to a try block, it must be DU on >> normal completion of the try block. >> >> Can you simplify further, while still preventing `this` calls >> inside a try block?? I don't think so, since we might want to >> allow a try block before the super/this call. >> >> >> Ok thanks. I admit I'm getting a little out of my league here. >> >> Does this sound correct? >> >> ?The JLS will be modified as follows: >> >> ?* Remove the requirement that `super()` or `this()` appear as the >> first statement in a constructor >> ?* Add superclass initialization to the existing constructor dataflow >> analysis as follows: >> ???? * The `this` reference is considered DU on entry to the constructor >> ? ? ?* Before a `this()` or `super()` call, the `this` reference must >> be DU >> ? ? ?* After a `this()` or `super()` call, the `this` reference is >> considered DA >> ???? * Before normal completion of the constructor, the `this` >> reference must be DA >> ???? * If `this` is DU on entry to a `try` block, it must be DU on >> normal completion of the `try` block >> ? ? ?* If no explicit `this()` or `super()` appears in a constructor, >> it is treated as if the first line of the constructor were `super()` >> ?* Add the following restrictions on constructors: >> ? ? ?* No access to `this`, other than assignments to fields, may >> occur unless `this` is DA >> ? ? ?* `super()` and `this()` may not appear within any `try { }` block >> ?* Clarify that non-static field initializers and initialization >> blocks are executed immediately after `super()` invocation, wherever >> it occurs (see "Initialization Order" below) >> >> >> Thanks, >> ?-Archie >> >> -- >> Archie L. Cobbs > -------------- next part -------------- An HTML attachment was scrubbed... URL: From robbepincket at live.be Tue Jan 24 23:18:20 2023 From: robbepincket at live.be (Robbe Pincket) Date: Tue, 24 Jan 2023 23:18:20 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> Message-ID: On 2023-01-24 00:42 UTC, Brian Goetz wrote: > Yes, substitute "normal completion" for "exit". I think I see what you mean. Still I think the original might be more descriptive? > * Add the requirement that `super()` and `this()` may not appear > within any `try { }` block Additionally, I think it would need to be extended to prevent calling `super()` or `this()` in lambdas? Or to mirror some other parts of the spec, a constructor call can?t be enclosed by a try block? ---- On 2023-01-24 20:11 UTC, Archie Cobbs wrote: > This made me realize there is another missing requirement: > > - Upon normal return from a constructor, the `this` reference must be DA > > Wouldn't that requirement subsume the one about try blocks? What I mean is, the normal dataflow analysis already takes care of try blocks, and what we care about is the DA/DU state when the constructor eventually returns. > > Thanks, > -Archie I think that only prevents "try catch" and not "try finally" (or "try with resources"). Actually that made me realize that in "try catch finally" or "try catch with resources", `this` or `super` calls shouldn't appear in any of the catch blocks either. ---- On 2023-01-24 20:21 UTC, Brian Goetz wrote: > You can simplify the rule about try blocks to: > > - if `this` is DU on entry to a try block, it must be DU on normal completion of the try block. > > Can you simplify further, while still preventing `this` calls inside a try block? I don't think so, since we might want to allow a try block before the super/this call. What about - At each point in the program, if `this` is not DA, it must be DU I think that covers all try cases? Kind regards Robbe Pincket -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Jan 25 07:03:14 2023 From: redio.development at gmail.com (Red IO) Date: Wed, 25 Jan 2023 08:03:14 +0100 Subject: Constructor Interfaces Message-ID: Summary ------- Enable a parameterized class to constrain the parameterized type to be constructible with a given list of parameters. Motivation ---------- It is possible since JDK 8 to get a constructor (method) reference of an object. This allowed for the creation of an unknown class with a known constructor reference. But currently the only way to obtain such reference is at call site like this: Box stringBox = new Box<>(String::new); It is inconvenient for the user to supply the the reference themselves and can confuse them as the type of the parameter is something like Supplier which doesn't require the pased reference to be a constructor. It also clutters api's like "toArray" which requires an IntFunction to be type safe. Description ----------- ConstructorInterface A ConstructorInterface is a special kind of interface similar to a FunctionalInterface. It also has similar constraints. It only allows abstract constructors and no other abstract methods. It can declare multiple constructors though. The definition of such interface would look similar to this: @ConstructorInterface //optional validation like FunctionalInterfaces public interface DefaultConstructible { new(); new(char[] chars); } A parameterized type could declare this interface as a type bound for its parameter and therefore enabling it to be constructed safely. Like this: public class Box { public Box() { E newElement = new E(); } } The containing type is not forced to implement the ContructorInterface explicitly. It is implicitly implemented if the required constructor(s) is(are) present. public static void main(String[] args) { Box stringBox = new Box<>(); //compiles because String has the required constructors. Box dateBox new Box<>(); error: java.sql.Data does not satisfy the type bound DefaultConstructible } The interface might not be implemented by any class, since it doesn't follow the inheritance rule that extending classes of those who implement it also implement it. This requirement comes from the fact that extending classes do not necessarily need to have the same constructor signature and therefore don't qualify the requirements for the interface. Another option would be that extending classes of classes that implement a constructor interface explicitly are also required to supply the necessary constructors. class Foo implements DefaultConstructable { //both required by the interface public Foo() {} public Foo(char[] chars) {} } class Bar extends Foo { //the requirement for the required constructors is passed down. public Bar() {} public Bar(char[] chars) {} } public static T createT() { return new T(); } public T wrapper() { return createT(); } This would technically work but would require a lot of static analysis to find the real type of T to call its constructor. Restricting the use of "new T()" to type parameters that specify a constructor interface directly and only allow those to be resolved with a concrete type rather than another type parameter. Alternatives ------------ An alternative would be to introduce new syntax to restrict the ability of certain constructors on a parameter type. Like c# does (but only for the default constructor) : public static T foo() where T: new() { return new T(); } In java: public static T foo() { return new T(); } The downside of this approach is obviously the introduction of new syntax rather than reusing the interface/inheritance syntax. Another alternative to this approach could be to implement static abstract methods. This would allow an interface to mandate a static Factory Method. The downside of this approach is that it requires the parameter class to actually implement the interface and the concept of type erasure would need to be addressed for static abstract methods to work. In contrast the ConstructorInterface enables every class that matches its contract to pass the type bound. Risks and Assumptions --------------------- As mentioned before the restriction the interface is giving on a type bound is different to normal interfaces, it restricts by its containing abstract constructors not by the type itself. It also makes use of the new operator on type variables. -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Wed Jan 25 13:03:10 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Wed, 25 Jan 2023 13:03:10 +0000 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: Hi. By the time the Box constructor runs it doesn?t know what E?s concrete type is. This has both advantages and disadvantages, but it?s the way things work now. In general, there are lots of annoyances that changes to the language may solve, but a change to the language also invariably introduces its own annoyances (for one, it makes the language more complex and requires people to learn how this works). So the trick is not so much finding a solution to a problem, but finding a problem that?s large and serious enough ? it can perhaps be very common or it could be one that leads to hard-to-find bugs ? to justify a particular language change. For example, in this case you may want to consider a constructor as a special case of a static method; maybe the problem you?re addressing isn?t large enough to justify this kind of ?constructor trait", but *maybe* a more general one that has to do with static methods in general could be. ? Ron > On 25 Jan 2023, at 07:03, Red IO wrote: > > Summary > ------- > > Enable a parameterized class to constrain the parameterized type to be constructible with a given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor (method) reference of an object. This allowed for the creation of an unknown class with a known constructor reference. But currently the only way to obtain such reference is at call site like this: > > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the reference themselves and can confuse them as the type of the parameter is something like Supplier which doesn't require the pased reference to be a constructor. > It also clutters api's like "toArray" which requires an IntFunction to be type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a FunctionalInterface. It also has similar constraints. It only allows abstract constructors and no other abstract methods. It can declare multiple constructors though. The definition of such interface would look similar to this: > > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface as a type bound for its parameter and therefore enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface explicitly. It is implicitly implemented if the required constructor(s) is(are) present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the required constructors. > Box dateBox new Box<>(); error: java.sql.Data does not satisfy the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't follow the inheritance rule that extending classes of those who implement it also implement it. This requirement comes from the fact that extending classes do not necessarily need to have the same constructor signature and therefore don't qualify the requirements for the interface. Another option would be that extending classes of classes that implement a constructor interface explicitly are also required to supply the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis to find the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a constructor interface directly and only allow those to be resolved with a concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the ability of certain constructors on a parameter type. Like c# does (but only for the default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new syntax rather than reusing the interface/inheritance syntax. > > Another alternative to this approach could be to implement static abstract methods. This would allow an interface to mandate a static Factory Method. The downside of this approach is that it requires the parameter class to actually implement the interface and the concept of type erasure would need to be addressed for static abstract methods to work. In contrast the ConstructorInterface enables every class that matches its contract to pass the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface is giving on a type bound is different to normal interfaces, it restricts by its containing abstract constructors not by the type itself. It also makes use of the new operator on type variables. > From michal at kleczek.org Wed Jan 25 13:21:17 2023 From: michal at kleczek.org (=?utf-8?Q?Micha=C5=82_K=C5=82eczek?=) Date: Wed, 25 Jan 2023 14:21:17 +0100 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: Hi, I would say: if going this direction then why not down the rabbit hole and implement full metaclasses like described as a possible Java extension 20 years ago here: https://www.cs.tufts.edu/~nr/cs257/archive/neal-glew/mcrt/Fortress/p109-allen.pdf? p109-allen PDF Document ? 241 KB Thanks, Michal > On 25 Jan 2023, at 08:03, Red IO wrote: > > Summary > ------- > > Enable a parameterized class to constrain the parameterized type to be constructible with a given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor (method) reference of an object. This allowed for the creation of an unknown class with a known constructor reference. But currently the only way to obtain such reference is at call site like this: > > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the reference themselves and can confuse them as the type of the parameter is something like Supplier which doesn't require the pased reference to be a constructor. > It also clutters api's like "toArray" which requires an IntFunction to be type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a FunctionalInterface. It also has similar constraints. It only allows abstract constructors and no other abstract methods. It can declare multiple constructors though. The definition of such interface would look similar to this: > > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface as a type bound for its parameter and therefore enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface explicitly. It is implicitly implemented if the required constructor(s) is(are) present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the required constructors. > Box dateBox new Box<>(); error: java.sql.Data does not satisfy the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't follow the inheritance rule that extending classes of those who implement it also implement it. This requirement comes from the fact that extending classes do not necessarily need to have the same constructor signature and therefore don't qualify the requirements for the interface. Another option would be that extending classes of classes that implement a constructor interface explicitly are also required to supply the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis to find the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a constructor interface directly and only allow those to be resolved with a concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the ability of certain constructors on a parameter type. Like c# does (but only for the default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new syntax rather than reusing the interface/inheritance syntax. > > Another alternative to this approach could be to implement static abstract methods. This would allow an interface to mandate a static Factory Method. The downside of this approach is that it requires the parameter class to actually implement the interface and the concept of type erasure would need to be addressed for static abstract methods to work. In contrast the ConstructorInterface enables every class that matches its contract to pass the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface is giving on a type bound is different to normal interfaces, it restricts by its containing abstract constructors not by the type itself. It also makes use of the new operator on type variables. > -------------- next part -------------- An HTML attachment was scrubbed... URL: -------------- next part -------------- A non-text attachment was scrubbed... Name: preview.png Type: image/png Size: 317158 bytes Desc: not available URL: From forax at univ-mlv.fr Wed Jan 25 13:51:40 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Wed, 25 Jan 2023 14:51:40 +0100 (CET) Subject: Constructor Interfaces In-Reply-To: References: Message-ID: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> We may need something like this for Valhalla, when we will revisit how to constraint the type arguments of universal generics. The kind of constraints you describe on type parameters already exist in C# or TypeScript and was more recently introduced in Go, and there is the type class of Haskell too. regards, R?mi > From: "Red IO" > To: "amber-dev" > Sent: Wednesday, January 25, 2023 8:03:14 AM > Subject: Constructor Interfaces > Summary > ------- > Enable a parameterized class to constrain the parameterized type to be > constructible with a given list of parameters. > Motivation > ---------- > It is possible since JDK 8 to get a constructor (method) reference of an object. > This allowed for the creation of an unknown class with a known constructor > reference. But currently the only way to obtain such reference is at call site > like this: > Box stringBox = new Box<>(String::new); > It is inconvenient for the user to supply the the reference themselves and can > confuse them as the type of the parameter is something like Supplier > which doesn't require the pased reference to be a constructor. > It also clutters api's like "toArray" which requires an IntFunction to be type > safe. > Description > ----------- > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a > FunctionalInterface. It also has similar constraints. It only allows abstract > constructors and no other abstract methods. It can declare multiple > constructors though. The definition of such interface would look similar to > this: > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > A parameterized type could declare this interface as a type bound for its > parameter and therefore enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface > explicitly. It is implicitly implemented if the required constructor(s) is(are) > present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the required > constructors. > Box dateBox new Box<>(); error: java.sql.Data does not satisfy > the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't follow the > inheritance rule that extending classes of those who implement it also > implement it. This requirement comes from the fact that extending classes do > not necessarily need to have the same constructor signature and therefore don't > qualify the requirements for the interface. Another option would be that > extending classes of classes that implement a constructor interface explicitly > are also required to supply the necessary constructors. > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > public static T createT() { > return new T(); > } > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis to find > the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a constructor > interface directly and only allow those to be resolved with a concrete type > rather than another type parameter. > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the ability of > certain constructors on a parameter type. Like c# does (but only for the > default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new syntax rather > than reusing the interface/inheritance syntax. > Another alternative to this approach could be to implement static abstract > methods. This would allow an interface to mandate a static Factory Method. The > downside of this approach is that it requires the parameter class to actually > implement the interface and the concept of type erasure would need to be > addressed for static abstract methods to work. In contrast the > ConstructorInterface enables every class that matches its contract to pass the > type bound. > Risks and Assumptions > --------------------- > As mentioned before the restriction the interface is giving on a type bound is > different to normal interfaces, it restricts by its containing abstract > constructors not by the type itself. It also makes use of the new operator on > type variables. -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Jan 25 13:42:01 2023 From: redio.development at gmail.com (Red IO) Date: Wed, 25 Jan 2023 14:42:01 +0100 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: Yes, as I mentioned in the alternative section this idea intersects with the concept of static abstract methods. The problem with the Box constructor not knowing the constructor of T would be solved by static analysis in my concept. public interface DefaultConstructable { new(); new(char[] chars); } class Box { public Box() { T t = new T(); T t2 = new T({ 'H', 'I' }); } } Box box = new Box<>(); Would be desugared to: public interface DefaultConstructable { T $ctor(); T $ctor(char[] chars); } class Box { private final DefaultConstructable $ctorT; public Box(DefaultConstructable $ctorT) { this.$ctorT = $ctorT; T t = $ctorT.$ctor(); T t2 = $ctorT.$ctor({ 'H', 'I' }); } } //this part would be implemented like a lambda with multiple methods/multiple lambdas but I have no idea what code lamdas actually generate. //So I put an anonymous class dummy here to make my point. Box box = new Box<>(new DefaultConstructable<>() { public String $ctor() { return new String(); } public String $ctor(char[] chars) { return new String(chars); } }); And I think the solution is pretty reasonable with no actual change in the runtime or compiler. Just some static analysis and desugaring before compilation. The only tricky part comes when type variables are passed to type variables and the static analysis can't find and verify the concrete type passed to in this case the Box constructor. But an algorithm unwinding all type variables to its concrete type isn't difficult I actually did it already and created an runtime type variable analysis tool. (since it needs to verify the bound of DefaultConstructable and generate the delegates to the actual constructors. On Wed, Jan 25, 2023, 14:03 Ron Pressler wrote: > Hi. > > By the time the Box constructor runs it doesn?t know what E?s concrete > type is. This has both advantages and disadvantages, but it?s the way > things work now. > > In general, there are lots of annoyances that changes to the language may > solve, but a change to the language also invariably introduces its own > annoyances (for one, it makes the language more complex and requires people > to learn how this works). So the trick is not so much finding a solution to > a problem, but finding a problem that?s large and serious enough ? it can > perhaps be very common or it could be one that leads to hard-to-find bugs ? > to justify a particular language change. For example, in this case you may > want to consider a constructor as a special case of a static method; maybe > the problem you?re addressing isn?t large enough to justify this kind of > ?constructor trait", but *maybe* a more general one that has to do with > static methods in general could be. > > ? Ron > > > On 25 Jan 2023, at 07:03, Red IO wrote: > > > > Summary > > ------- > > > > Enable a parameterized class to constrain the parameterized type to be > constructible with a given list of parameters. > > > > > > > > Motivation > > ---------- > > > > It is possible since JDK 8 to get a constructor (method) reference of an > object. This allowed for the creation of an unknown class with a known > constructor reference. But currently the only way to obtain such reference > is at call site like this: > > > > Box stringBox = new Box<>(String::new); > > > > It is inconvenient for the user to supply the the reference themselves > and can confuse them as the type of the parameter is something like > Supplier which doesn't require the pased reference to be a > constructor. > > It also clutters api's like "toArray" which requires an IntFunction to > be type safe. > > > > Description > > ----------- > > > > ConstructorInterface > > A ConstructorInterface is a special kind of interface similar to a > FunctionalInterface. It also has similar constraints. It only allows > abstract constructors and no other abstract methods. It can declare > multiple constructors though. The definition of such interface would look > similar to this: > > > > @ConstructorInterface //optional validation like > FunctionalInterfaces > > public interface DefaultConstructible { > > new(); > > new(char[] chars); > > } > > > > A parameterized type could declare this interface as a type bound for > its parameter and therefore enabling it to be constructed safely. Like this: > > public class Box { > > public Box() { > > E newElement = new E(); > > } > > } > > The containing type is not forced to implement the ContructorInterface > explicitly. It is implicitly implemented if the required constructor(s) > is(are) present. > > public static void main(String[] args) { > > Box stringBox = new Box<>(); //compiles because > String has the required constructors. > > Box dateBox new Box<>(); error: > java.sql.Data does not satisfy the type bound DefaultConstructible > > } > > The interface might not be implemented by any class, since it doesn't > follow the inheritance rule that extending classes of those who implement > it also implement it. This requirement comes from the fact that extending > classes do not necessarily need to have the same constructor signature and > therefore don't qualify the requirements for the interface. Another option > would be that extending classes of classes that implement a constructor > interface explicitly are also required to supply the necessary constructors. > > > > class Foo implements DefaultConstructable { > > //both required by the interface > > public Foo() {} > > public Foo(char[] chars) {} > > } > > > > class Bar extends Foo { > > //the requirement for the required constructors is passed > down. > > public Bar() {} > > public Bar(char[] chars) {} > > } > > > > > > > > public static T createT() { > > return new T(); > > } > > > > public T wrapper() { > > return createT(); > > } > > This would technically work but would require a lot of static analysis > to find the real type of T to call its constructor. > > Restricting the use of "new T()" to type parameters that specify a > constructor interface directly and only allow those to be resolved with a > concrete type rather than another type parameter. > > > > Alternatives > > ------------ > > An alternative would be to introduce new syntax to restrict the ability > of certain constructors on a parameter type. Like c# does (but only for the > default constructor) : > > public static T foo() where T: new() { > > return new T(); > > } > > In java: > > public static T foo() { > > return new T(); > > } > > The downside of this approach is obviously the introduction of new > syntax rather than reusing the interface/inheritance syntax. > > > > Another alternative to this approach could be to implement static > abstract methods. This would allow an interface to mandate a static Factory > Method. The downside of this approach is that it requires the parameter > class to actually implement the interface and the concept of type erasure > would need to be addressed for static abstract methods to work. In contrast > the ConstructorInterface enables every class that matches its contract to > pass the type bound. > > > > > > > > Risks and Assumptions > > --------------------- > > > > As mentioned before the restriction the interface is giving on a type > bound is different to normal interfaces, it restricts by its containing > abstract constructors not by the type itself. It also makes use of the new > operator on type variables. > > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Jan 25 14:17:34 2023 From: redio.development at gmail.com (Red IO) Date: Wed, 25 Jan 2023 15:17:34 +0100 Subject: Constructor Interfaces In-Reply-To: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> Message-ID: I proposed an idea (to Valhalla) to overcome type erasure that used the same idea of desugering and a hidden argument that carries the erased types class variable inside the generic context, but it was rejected as a to naive approach or something and they where "already working on different solutions for some time". Great regards RedIODev On Wed, Jan 25, 2023, 14:51 Remi Forax wrote: > We may need something like this for Valhalla, when we will revisit how to > constraint the type arguments of universal generics. > > The kind of constraints you describe on type parameters already exist in > C# or TypeScript and was more recently introduced in Go, and there is the > type class of Haskell too. > > regards, > R?mi > > ------------------------------ > > *From: *"Red IO" > *To: *"amber-dev" > *Sent: *Wednesday, January 25, 2023 8:03:14 AM > *Subject: *Constructor Interfaces > > Summary > ------- > > Enable a parameterized class to constrain the parameterized type to be > constructible with a given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor (method) reference of an > object. This allowed for the creation of an unknown class with a known > constructor reference. But currently the only way to obtain such reference > is at call site like this: > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the reference themselves and > can confuse them as the type of the parameter is something like > Supplier which doesn't require the pased reference to be a > constructor. > It also clutters api's like "toArray" which requires an IntFunction to be > type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a > FunctionalInterface. It also has similar constraints. It only allows > abstract constructors and no other abstract methods. It can declare > multiple constructors though. The definition of such interface would look > similar to this: > > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface as a type bound for its > parameter and therefore enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface > explicitly. It is implicitly implemented if the required constructor(s) > is(are) present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the > required constructors. > Box dateBox new Box<>(); error: java.sql.Data does not > satisfy the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't > follow the inheritance rule that extending classes of those who implement > it also implement it. This requirement comes from the fact that extending > classes do not necessarily need to have the same constructor signature and > therefore don't qualify the requirements for the interface. Another option > would be that extending classes of classes that implement a constructor > interface explicitly are also required to supply the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis to > find the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a > constructor interface directly and only allow those to be resolved with a > concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the ability of > certain constructors on a parameter type. Like c# does (but only for the > default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new syntax > rather than reusing the interface/inheritance syntax. > > Another alternative to this approach could be to implement static abstract > methods. This would allow an interface to mandate a static Factory Method. > The downside of this approach is that it requires the parameter class to > actually implement the interface and the concept of type erasure would need > to be addressed for static abstract methods to work. In contrast the > ConstructorInterface enables every class that matches its contract to pass > the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface is giving on a type > bound is different to normal interfaces, it restricts by its containing > abstract constructors not by the type itself. It also makes use of the new > operator on type variables. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 15:11:00 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 10:11:00 -0500 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: This is a good example of a "you can, but you probably shouldn't" language feature.? The power-to-weight ratio isn't favorable; it is a lot of new machinery and concept to move the ball forward a small amount. And as soon as the ball is moved forward by that amount, we will immediately be confronted by the next thing we can't do, and the solutions are likely to be an increasingly complex sequence of worse power-to-weight ratio ideas.? (Careful observers of Java history might note that this phenomenon is especially evident in any proposal surrounding annotations.) As Michael K pointed out, other languages have explored more general, but more suitable, answers here; what you're looking for is a witness to conformance to a type class.? (Our friends in C# have pursued something similar through abstract statics; for various reasons, that's less of a good match for Java than for C#.)? This is not a small ask; its significant new complexity, but the power gained is much greater.? If we were to choose to invest in solving problems like this one, that would likely be the path, but this is a big lift and we have other big things on our plate right now. As a general note, while it is fun to imagine new language features, language design needs to be a holistic process.? If we did a hundred "point" features like this, what are the chances that the whole would hold together?? If we did this feature, what other potential feature directions are we implicitly foreclosing on?? These are the questions we address ourselves to when choosing what features to consider and not. On 1/25/2023 2:03 AM, Red IO wrote: > Summary > ------- > > Enable a parameterized class to constrain the parameterized type to be > constructible with a given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor (method) reference of > an object. This allowed for the creation of an unknown class with a > known constructor reference. But currently the only way to obtain such > reference is at call site like this: > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the reference themselves > and can confuse them as the type of the parameter is something like > Supplier which doesn't require the pased reference to be a > constructor. > It also clutters api's like "toArray" which requires an IntFunction to > be type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a > FunctionalInterface. It also has similar constraints. It only allows > abstract constructors and no other abstract methods. It can declare > multiple constructors though. The definition of such interface would > look similar to this: > > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface as a type bound for > its parameter and therefore enabling it to be constructed safely. Like > this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface > explicitly. It is implicitly implemented if the required > constructor(s) is(are) present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the > required constructors. > Box dateBox new Box<>(); error: java.sql.Data does not > satisfy the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't > follow the inheritance rule that extending classes of those who > implement it also implement it. This requirement comes from the fact > that extending classes do not necessarily need to have the same > constructor signature and therefore don't qualify the requirements for > the interface. Another option would be that extending classes of > classes that implement a constructor interface explicitly are also > required to supply the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return?new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis > to find the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a > constructor interface directly and only allow those to be resolved > with a concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the > ability of certain constructors on a parameter type. Like c# does (but > only for the default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new > syntax rather than reusing the interface/inheritance syntax. > > Another alternative to this approach could be to implement static > abstract methods. This would allow an interface to mandate a static > Factory Method. The downside of this approach is that it requires the > parameter class to actually implement the interface and the concept of > type erasure would need to be addressed for static abstract methods to > work. In contrast the ConstructorInterface enables every class that > matches its contract to pass the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface is giving on a type > bound is different to normal interfaces, it restricts by its > containing abstract constructors not by the type itself. It also makes > use of the new operator on type variables. > -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Jan 25 15:54:07 2023 From: redio.development at gmail.com (Red IO) Date: Wed, 25 Jan 2023 16:54:07 +0100 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: I'm not sure how big of a closing factor this implementation would have. Since the whole implementation is opaque to everyone but the compiler. If implemented that way it would be vital to guard the information carrying field from the user (against reflection for example). If done correctly this would be so opaque that a full implementation change would be possible. The sole requirement would be that you could use the type variable the same way in the new implementation. As I was exploring a possible implementation in my last mail I realized that it (by design) is 90% preprocessor. I think I will continue exploring it by trying to implement it using an annotation processor and explore potential problems while using it. Of cause the annotation processor will be ugly to use and for development only. Great regards RedIODev On Wed, Jan 25, 2023, 16:11 Brian Goetz wrote: > This is a good example of a "you can, but you probably shouldn't" language > feature. The power-to-weight ratio isn't favorable; it is a lot of new > machinery and concept to move the ball forward a small amount. And as soon > as the ball is moved forward by that amount, we will immediately be > confronted by the next thing we can't do, and the solutions are likely to > be an increasingly complex sequence of worse power-to-weight ratio ideas. > (Careful observers of Java history might note that this phenomenon is > especially evident in any proposal surrounding annotations.) > > As Michael K pointed out, other languages have explored more general, but > more suitable, answers here; what you're looking for is a witness to > conformance to a type class. (Our friends in C# have pursued something > similar through abstract statics; for various reasons, that's less of a > good match for Java than for C#.) This is not a small ask; its significant > new complexity, but the power gained is much greater. If we were to choose > to invest in solving problems like this one, that would likely be the path, > but this is a big lift and we have other big things on our plate right > now. > > As a general note, while it is fun to imagine new language features, > language design needs to be a holistic process. If we did a hundred > "point" features like this, what are the chances that the whole would hold > together? If we did this feature, what other potential feature directions > are we implicitly foreclosing on? These are the questions we address > ourselves to when choosing what features to consider and not. > > > On 1/25/2023 2:03 AM, Red IO wrote: > > Summary > ------- > > Enable a parameterized class to constrain the parameterized type to be > constructible with a given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor (method) reference of an > object. This allowed for the creation of an unknown class with a known > constructor reference. But currently the only way to obtain such reference > is at call site like this: > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the reference themselves and > can confuse them as the type of the parameter is something like > Supplier which doesn't require the pased reference to be a > constructor. > It also clutters api's like "toArray" which requires an IntFunction to be > type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of interface similar to a > FunctionalInterface. It also has similar constraints. It only allows > abstract constructors and no other abstract methods. It can declare > multiple constructors though. The definition of such interface would look > similar to this: > > @ConstructorInterface //optional validation like FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface as a type bound for its > parameter and therefore enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the ContructorInterface > explicitly. It is implicitly implemented if the required constructor(s) > is(are) present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles because String has the > required constructors. > Box dateBox new Box<>(); error: java.sql.Data does not > satisfy the type bound DefaultConstructible > } > The interface might not be implemented by any class, since it doesn't > follow the inheritance rule that extending classes of those who implement > it also implement it. This requirement comes from the fact that extending > classes do not necessarily need to have the same constructor signature and > therefore don't qualify the requirements for the interface. Another option > would be that extending classes of classes that implement a constructor > interface explicitly are also required to supply the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a lot of static analysis to > find the real type of T to call its constructor. > Restricting the use of "new T()" to type parameters that specify a > constructor interface directly and only allow those to be resolved with a > concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to restrict the ability of > certain constructors on a parameter type. Like c# does (but only for the > default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the introduction of new syntax > rather than reusing the interface/inheritance syntax. > > Another alternative to this approach could be to implement static abstract > methods. This would allow an interface to mandate a static Factory Method. > The downside of this approach is that it requires the parameter class to > actually implement the interface and the concept of type erasure would need > to be addressed for static abstract methods to work. In contrast the > ConstructorInterface enables every class that matches its contract to pass > the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface is giving on a type > bound is different to normal interfaces, it restricts by its containing > abstract constructors not by the type itself. It also makes use of the new > operator on type variables. > > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 16:24:06 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 11:24:06 -0500 Subject: Constructor Interfaces In-Reply-To: References: Message-ID: <30bd6b64-091f-51ee-04e1-768aa5f7444e@oracle.com> I think you may have misunderstood.? We don't use annotations to extend the language in this way at all; if you want a new type system feature (such as new kinds of bounds on type variables), you have to extend the language honestly.? My comments below were related not to the annotation-mockup of the feature, but to the actual feature itself. What you're doing is inventing an entirely new kind of implements-interface relation, one which the usual inheritance rule: ??? T implements I?? S extends T ??? ---------------------------- ?? ??????? S implements I does not apply. That's not to say that it can't be done, but I think you're dramatically underestimating what you're suggesting. I get it; what you really want to be saying is "gee, it would be nice if we could express constraints on type variables that the type being substituted provides static methods and/or constructors".? And it would be nice, but it's not a new observation, and the answers are complicated. On 1/25/2023 10:54 AM, Red IO wrote: > I'm not sure how big of a closing factor this implementation would > have. Since the whole implementation is opaque to everyone but the > compiler. If implemented that way it would be vital to guard the > information carrying field from the user (against reflection for > example). If done correctly this would be so opaque that a full > implementation change would be possible. The sole requirement would be > that you could use the type variable the same way in the new > implementation. > As I was exploring a possible implementation in my last mail I > realized that it (by design) is 90% preprocessor. I think I will > continue exploring it by trying to implement it using an annotation > processor and explore potential problems while using it. > Of cause the annotation processor will be ugly to use and for > development only. > > Great regards > RedIODev > > On Wed, Jan 25, 2023, 16:11 Brian Goetz wrote: > > This is a good example of a "you can, but you probably shouldn't" > language feature.? The power-to-weight ratio isn't favorable; it > is a lot of new machinery and concept to move the ball forward a > small amount.? And as soon as the ball is moved forward by that > amount, we will immediately be confronted by the next thing we > can't do, and the solutions are likely to be an increasingly > complex sequence of worse power-to-weight ratio ideas. (Careful > observers of Java history might note that this phenomenon is > especially evident in any proposal surrounding annotations.) > > As Michael K pointed out, other languages have explored more > general, but more suitable, answers here; what you're looking for > is a witness to conformance to a type class.? (Our friends in C# > have pursued something similar through abstract statics; for > various reasons, that's less of a good match for Java than for > C#.)? This is not a small ask; its significant new complexity, but > the power gained is much greater.? If we were to choose to invest > in solving problems like this one, that would likely be the path, > but this is a big lift and we have other big things on our plate > right now. > > As a general note, while it is fun to imagine new language > features, language design needs to be a holistic process.? If we > did a hundred "point" features like this, what are the chances > that the whole would hold together?? If we did this feature, what > other potential feature directions are we implicitly foreclosing > on?? These are the questions we address ourselves to when choosing > what features to consider and not. > > > On 1/25/2023 2:03 AM, Red IO wrote: >> Summary >> ------- >> >> Enable a parameterized class to constrain the parameterized type >> to be constructible with a given list of parameters. >> >> >> >> Motivation >> ---------- >> >> It is possible since JDK 8 to get a constructor (method) >> reference of an object. This allowed for the creation of an >> unknown class with a known constructor reference. But currently >> the only way to obtain such reference is at call site like this: >> Box stringBox = new Box<>(String::new); >> >> It is inconvenient for the user to supply the the reference >> themselves and can confuse them as the type of the parameter is >> something like Supplier which doesn't require the pased >> reference to be a constructor. >> It also clutters api's like "toArray" which requires an >> IntFunction to be type safe. >> >> Description >> ----------- >> >> ConstructorInterface >> A ConstructorInterface is a special kind of interface similar to >> a FunctionalInterface. It also has similar constraints. It only >> allows abstract constructors and no other abstract methods. It >> can declare multiple constructors though. The definition of such >> interface would look similar to this: >> >> @ConstructorInterface //optional validation like FunctionalInterfaces >> public interface DefaultConstructible { >> new(); >> new(char[] chars); >> } >> >> A parameterized type could declare this interface as a type bound >> for its parameter and therefore enabling it to be constructed >> safely. Like this: >> public class Box { >> public Box() { >> E newElement = new E(); >> } >> } >> The containing type is not forced to implement the >> ContructorInterface explicitly. It is implicitly implemented if >> the required constructor(s) is(are) present. >> public static void main(String[] args) { >> Box stringBox = new Box<>(); //compiles because String >> has the required constructors. >> Box dateBox new Box<>(); error: java.sql.Data does >> not satisfy the type bound DefaultConstructible >> } >> The interface might not be implemented by any class, since it >> doesn't follow the inheritance rule that extending classes of >> those who implement it also implement it. This requirement comes >> from the fact that extending classes do not necessarily need to >> have the same constructor signature and therefore don't qualify >> the requirements for the interface. Another option would be that >> extending classes of classes that implement a constructor >> interface explicitly are also required to supply the necessary >> constructors. >> >> class Foo implements DefaultConstructable { >> //both required by the interface >> public Foo() {} >> public Foo(char[] chars) {} >> } >> >> class Bar extends Foo { >> //the requirement for the required constructors is passed down. >> public Bar() {} >> public Bar(char[] chars) {} >> } >> >> >> >> public static T createT() { >> return?new T(); >> } >> >> public T wrapper() { >> return createT(); >> } >> This would technically work but would require a lot of static >> analysis to find the real type of T to call its constructor. >> Restricting the use of "new T()" to type parameters that specify >> a constructor interface directly and only allow those to be >> resolved with a concrete type rather than another type parameter. >> >> Alternatives >> ------------ >> An alternative would be to introduce new syntax to restrict the >> ability of certain constructors on a parameter type. Like c# does >> (but only for the default constructor) : >> public static T foo() where T: new() { >> return new T(); >> } >> In java: >> public static T foo() { >> return new T(); >> } >> The downside of this approach is obviously the introduction of >> new syntax rather than reusing the interface/inheritance syntax. >> >> Another alternative to this approach could be to implement static >> abstract methods. This would allow an interface to mandate a >> static Factory Method. The downside of this approach is that it >> requires the parameter class to actually implement the interface >> and the concept of type erasure would need to be addressed for >> static abstract methods to work. In contrast the >> ConstructorInterface enables every class that matches its >> contract to pass the type bound. >> >> >> >> Risks and Assumptions >> --------------------- >> >> As mentioned before the restriction the interface is giving on a >> type bound is different to normal interfaces, it restricts by its >> containing abstract constructors not by the type itself. It also >> makes use of the new operator on type variables. >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Wed Jan 25 16:53:29 2023 From: redio.development at gmail.com (Red IO) Date: Wed, 25 Jan 2023 17:53:29 +0100 Subject: Constructor Interfaces In-Reply-To: <30bd6b64-091f-51ee-04e1-768aa5f7444e@oracle.com> References: <30bd6b64-091f-51ee-04e1-768aa5f7444e@oracle.com> Message-ID: I know that the final feature cannot be implemented with annotations. I also wasn't thinking of implementing the user facing sugar for this feature. The Anotation processor would explore the hidden part like the hidden data field and the creation of the call site expansion. The different notion of interface is a part of my idea, that is not required. It can be switched out with any other syntax carrying the same information. Like a where clause for example: class Box where T satisfies new() & new(char[]) {} But the concrete user facing api is secondary. The idea of the special interface was an approach to implement the new feature without reserving new keywords and syntax. (at least as little as possible). The current code that handles generic bounds wouldn't even need to change. Since the constructor interface preprocessor logic would remove the bound while parcing the bound. (of course it would need to run before) But this wouldn't solve user confusion since it looks like an interface bound it really isn't one. Maybe a mixed approach with a contextual keyword would be better for clarity, like: class Box {} What I will now do first is explore the inner workings of the preprocessing and the limitations of the approach. This will surface problems and or use cases now not obvious. Great regards RedIODev On Wed, Jan 25, 2023, 17:24 Brian Goetz wrote: > I think you may have misunderstood. We don't use annotations to extend > the language in this way at all; if you want a new type system feature > (such as new kinds of bounds on type variables), you have to extend the > language honestly. My comments below were related not to the > annotation-mockup of the feature, but to the actual feature itself. > > What you're doing is inventing an entirely new kind of > implements-interface relation, one which the usual inheritance rule: > > T implements I S extends T > ---------------------------- > S implements I > > does not apply. > > That's not to say that it can't be done, but I think you're dramatically > underestimating what you're suggesting. > > I get it; what you really want to be saying is "gee, it would be nice if > we could express constraints on type variables that the type being > substituted provides static methods and/or constructors". And it would be > nice, but it's not a new observation, and the answers are complicated. > > > On 1/25/2023 10:54 AM, Red IO wrote: > > I'm not sure how big of a closing factor this implementation would have. > Since the whole implementation is opaque to everyone but the compiler. If > implemented that way it would be vital to guard the information carrying > field from the user (against reflection for example). If done correctly > this would be so opaque that a full implementation change would be > possible. The sole requirement would be that you could use the type > variable the same way in the new implementation. > As I was exploring a possible implementation in my last mail I realized > that it (by design) is 90% preprocessor. I think I will continue exploring > it by trying to implement it using an annotation processor and explore > potential problems while using it. > Of cause the annotation processor will be ugly to use and for development > only. > > Great regards > RedIODev > > On Wed, Jan 25, 2023, 16:11 Brian Goetz wrote: > >> This is a good example of a "you can, but you probably shouldn't" >> language feature. The power-to-weight ratio isn't favorable; it is a lot >> of new machinery and concept to move the ball forward a small amount. And >> as soon as the ball is moved forward by that amount, we will immediately be >> confronted by the next thing we can't do, and the solutions are likely to >> be an increasingly complex sequence of worse power-to-weight ratio ideas. >> (Careful observers of Java history might note that this phenomenon is >> especially evident in any proposal surrounding annotations.) >> >> As Michael K pointed out, other languages have explored more general, but >> more suitable, answers here; what you're looking for is a witness to >> conformance to a type class. (Our friends in C# have pursued something >> similar through abstract statics; for various reasons, that's less of a >> good match for Java than for C#.) This is not a small ask; its significant >> new complexity, but the power gained is much greater. If we were to choose >> to invest in solving problems like this one, that would likely be the path, >> but this is a big lift and we have other big things on our plate right >> now. >> >> As a general note, while it is fun to imagine new language features, >> language design needs to be a holistic process. If we did a hundred >> "point" features like this, what are the chances that the whole would hold >> together? If we did this feature, what other potential feature directions >> are we implicitly foreclosing on? These are the questions we address >> ourselves to when choosing what features to consider and not. >> >> >> On 1/25/2023 2:03 AM, Red IO wrote: >> >> Summary >> ------- >> >> Enable a parameterized class to constrain the parameterized type to be >> constructible with a given list of parameters. >> >> >> >> Motivation >> ---------- >> >> It is possible since JDK 8 to get a constructor (method) reference of an >> object. This allowed for the creation of an unknown class with a known >> constructor reference. But currently the only way to obtain such reference >> is at call site like this: >> Box stringBox = new Box<>(String::new); >> >> It is inconvenient for the user to supply the the reference themselves >> and can confuse them as the type of the parameter is something like >> Supplier which doesn't require the pased reference to be a >> constructor. >> It also clutters api's like "toArray" which requires an IntFunction to be >> type safe. >> >> Description >> ----------- >> >> ConstructorInterface >> A ConstructorInterface is a special kind of interface similar to a >> FunctionalInterface. It also has similar constraints. It only allows >> abstract constructors and no other abstract methods. It can declare >> multiple constructors though. The definition of such interface would look >> similar to this: >> >> @ConstructorInterface //optional validation like FunctionalInterfaces >> public interface DefaultConstructible { >> new(); >> new(char[] chars); >> } >> >> A parameterized type could declare this interface as a type bound for its >> parameter and therefore enabling it to be constructed safely. Like this: >> public class Box { >> public Box() { >> E newElement = new E(); >> } >> } >> The containing type is not forced to implement the ContructorInterface >> explicitly. It is implicitly implemented if the required constructor(s) >> is(are) present. >> public static void main(String[] args) { >> Box stringBox = new Box<>(); //compiles because String has the >> required constructors. >> Box dateBox new Box<>(); error: java.sql.Data does not >> satisfy the type bound DefaultConstructible >> } >> The interface might not be implemented by any class, since it doesn't >> follow the inheritance rule that extending classes of those who implement >> it also implement it. This requirement comes from the fact that extending >> classes do not necessarily need to have the same constructor signature and >> therefore don't qualify the requirements for the interface. Another option >> would be that extending classes of classes that implement a constructor >> interface explicitly are also required to supply the necessary constructors. >> >> class Foo implements DefaultConstructable { >> //both required by the interface >> public Foo() {} >> public Foo(char[] chars) {} >> } >> >> class Bar extends Foo { >> //the requirement for the required constructors is passed down. >> public Bar() {} >> public Bar(char[] chars) {} >> } >> >> >> >> public static T createT() { >> return new T(); >> } >> >> public T wrapper() { >> return createT(); >> } >> This would technically work but would require a lot of static analysis to >> find the real type of T to call its constructor. >> Restricting the use of "new T()" to type parameters that specify a >> constructor interface directly and only allow those to be resolved with a >> concrete type rather than another type parameter. >> >> Alternatives >> ------------ >> An alternative would be to introduce new syntax to restrict the ability >> of certain constructors on a parameter type. Like c# does (but only for the >> default constructor) : >> public static T foo() where T: new() { >> return new T(); >> } >> In java: >> public static T foo() { >> return new T(); >> } >> The downside of this approach is obviously the introduction of new syntax >> rather than reusing the interface/inheritance syntax. >> >> Another alternative to this approach could be to implement static >> abstract methods. This would allow an interface to mandate a static Factory >> Method. The downside of this approach is that it requires the parameter >> class to actually implement the interface and the concept of type erasure >> would need to be addressed for static abstract methods to work. In contrast >> the ConstructorInterface enables every class that matches its contract to >> pass the type bound. >> >> >> >> Risks and Assumptions >> --------------------- >> >> As mentioned before the restriction the interface is giving on a type >> bound is different to normal interfaces, it restricts by its containing >> abstract constructors not by the type itself. It also makes use of the new >> operator on type variables. >> >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 18:49:25 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 13:49:25 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Message-ID: Thinking more on this -- I think there is significant simplicity dividend here if we relax our goals a little bit.? Supporting constructs such as ??????? if (bar) ??????????? this(f(bar)); ??????? else ??????????? this(g(bar), 0); would require a full DA/DU analysis, but if the goal is really "allow statements before the this/super", we can get by with a considerably simpler feature. On the latter path, we define a grammar production for "constructor body" that amounts to: ??? statement* ??? [super | this]? ??? statement* We further constrain the statement grammar / description to exclude `this(...)` or `super(...)` calls, since the only place they can appear is in a constructor, and now there's a place for them to explicitly live. We can use similar language to say "if there isn't a super/this, you get one for free at the top" as we do today. We can use similar "introduces a static context" approach for the statements prior to the super/this, and the super/this, as we do today.? This is enough to prevent use of `this`, explicitly or implicitly, in the statements preceding the explicit super/this, including in lambdas, try blocks, etc. I don't think there's any need to update DA/DU. This brings the spec footprint down considerably, while still eliminating complex/risky workarounds around "super first". On 1/24/2023 6:16 PM, Brian Goetz wrote: > Hit "send" a little too soon. > > The assertion that governs "no use of `this` in a super/this call" is > in 8.8.7.1: > >> An explicit constructor invocation statement introduces a static >> context (?8.1.3), >> which limits the use of constructs that refer to the current object. >> Notably, the >> keywords this and super are prohibited in a static context (?15.8.3, >> ?15.11.2), >> as are unqualified references to instance variables, instance >> methods, and type >> parameters of lexically enclosing declarations (?6.5.5.1, ?6.5.6.1, >> ?15.12.3). > > This needs to be generalized to speak about the use of `this` > throughout the constructor body; basically, that you can never use > `this` (explicitly or implicitly) prior to to the super/this call. > > There are a few ways you could do this: > > ?- A full-blown treatment of DA/DU for `this`; > ?- An extension of the "introduces a static context" used in this > section, that covers the entire initial segment of the constructor > body up through and including the this/super-call. > > Similarly, you'll need a way to restate the "if it doesn't start with > `this/super`, you get an implicit super" to the more flexible notion > being outlined here.? This is tricky because the obvious way to do > this is to run DA/DU on the explicit body of the constructor and ask > if `this` is DA at all points where the constructor could complete > normally, and if not, prepend a super() call and rerun DA/DU.? This > moves us from a strictly syntactic rule to one that appeals to a > complex analysis. > > We can simplify this analysis a lot by lowering the target, from one > that is based on DA to funneling through a single super/this choke > point, where a ctor body with an explicit super/this looks like: > > ??? statement* > ??? super/this call > ??? statement* > > This would rule out constructs like: > > ??? Foo() { > ??????? if (bar) > ??????????? this(f(bar)); > ??????? else > ??????????? this(g(bar), 0); > ??? } > > but is a lot simpler to specify and still offers the "stuff before > super" benefit. > > > > > > On 1/24/2023 6:01 PM, Brian Goetz wrote: >> The basic design seems sound enough.? Probably time to dig to the >> next level, which is assessing the spec impact. >> >> The places to start are Ch16 (definite assignment) and 8.8.7 >> (constructor bodies). >> >> On 1/24/2023 4:24 PM, Archie Cobbs wrote: >>> On Tue, Jan 24, 2023 at 2:21 PM Brian Goetz >>> wrote: >>> >>> >>>> This made me realize there is another missing requirement: >>>> >>>> * Upon normal return from a constructor, the `this` reference >>>> must be DA >>>> >>> >>> So, I think this is true by definition; on normal return from a >>> super/this/implicit super call, then `this` *is* DA. >>> >>> You can simplify the rule about try blocks to: >>> >>> ?- if `this` is DU on entry to a try block, it must be DU on >>> normal completion of the try block. >>> >>> Can you simplify further, while still preventing `this` calls >>> inside a try block?? I don't think so, since we might want to >>> allow a try block before the super/this call. >>> >>> >>> Ok thanks. I admit I'm getting a little out of my league here. >>> >>> Does this sound correct? >>> >>> ?The JLS will be modified as follows: >>> >>> ?* Remove the requirement that `super()` or `this()` appear as the >>> first statement in a constructor >>> ?* Add superclass initialization to the existing constructor >>> dataflow analysis as follows: >>> ???? * The `this` reference is considered DU on entry to the constructor >>> ? ? ?* Before a `this()` or `super()` call, the `this` reference >>> must be DU >>> ? ? ?* After a `this()` or `super()` call, the `this` reference is >>> considered DA >>> ???? * Before normal completion of the constructor, the `this` >>> reference must be DA >>> ???? * If `this` is DU on entry to a `try` block, it must be DU on >>> normal completion of the `try` block >>> ? ? ?* If no explicit `this()` or `super()` appears in a >>> constructor, it is treated as if the first line of the constructor >>> were `super()` >>> ?* Add the following restrictions on constructors: >>> ? ? ?* No access to `this`, other than assignments to fields, may >>> occur unless `this` is DA >>> ? ? ?* `super()` and `this()` may not appear within any `try { }` block >>> ?* Clarify that non-static field initializers and initialization >>> blocks are executed immediately after `super()` invocation, wherever >>> it occurs (see "Initialization Order" below) >>> >>> >>> Thanks, >>> ?-Archie >>> >>> -- >>> Archie L. Cobbs >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 25 19:06:33 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 25 Jan 2023 13:06:33 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 12:49 PM Brian Goetz wrote: > Thinking more on this -- I think there is significant simplicity dividend > here if we relax our goals a little bit. Supporting constructs such as > > if (bar) > this(f(bar)); > else > this(g(bar), 0); > > would require a full DA/DU analysis, but if the goal is really "allow > statements before the this/super", we can get by with a considerably > simpler feature. > Ugh - to be honest I really don't like this simplification. For example, it invalidates two of the five "housekeeping" examples in the current JEP draft ("choosing constructor at runtime" and "complex preparation"). The idea of superclass initialization working just like blank final field initialization is familiar and intuitive... and the implementation is straightforward to piggy-back on existing DU/DA dataflow analysis. > This brings the spec footprint down considerably, while still eliminating > complex/risky workarounds around "super first". > I agree that we need to think carefully about how to best update the spec. But I'm not ready to give up yet on the original plan... Put another way, if a reasonable language change is such a problem for the spec, then that's a problem to solve with the spec, not the language. Now I'm not a spec expert (it seems kind of analogous to being a patent lawyer) but what about this plan: 1. "Piggy-back" superclass initialization DA/DU on top of the existing spec for blank final fields - however you want to word that... 2. Specify that for any statement in a constructor: 1. If: 1. Superclass initialization is not DA at the beginning of the statement 2. The statement would not be legal in a static context 1. Then: 1. The statement is illegal, unless: 1. The statement is an assignment statement and the LHS of the statement is a non-static field of the new instance -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 19:23:10 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 14:23:10 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Message-ID: > This brings the spec footprint down considerably, while still > eliminating complex/risky workarounds around "super first". > > > Put another way, if a reasonable language change is such a problem for > the spec, then that's a problem to solve with the spec, not the language. Not sure what you mean; the spec is the language, and the language is the spec.? Many things that seem simple when describing them in terms of "use DA/DU to ..." or "use inference to ..." turn out to be complicated to specify -- which means the language changes are more complicated than they first seemed.? Gauging the spec impact is how we keep ourselves honest about the scope of language changes. > Now I'm not a spec expert (it seems kind of analogous to being a > patent lawyer) but what about this plan: This is obviously doable, but my recent comments (having looked at what the spec impact would be) is saying that this is a more complicated, more invasive language feature than the simpler "statements before super" feature.? Part of what I'm trying to do here is steer towards success by pruning the problem to one that can be achieved without spending years immersing yourself in specification. -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 25 20:05:55 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 25 Jan 2023 14:05:55 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 1:23 PM Brian Goetz wrote: > Not sure what you mean; the spec is the language, and the language is the > spec. Many things that seem simple when describing them in terms of "use > DA/DU to ..." or "use inference to ..." turn out to be complicated to > specify -- which means the language changes are more complicated than they > first seemed. Gauging the spec impact is how we keep ourselves honest > about the scope of language changes. > > This is obviously doable, but my recent comments (having looked at what > the spec impact would be) is saying that this is a more complicated, more > invasive language feature than the simpler "statements before super" > feature. Part of what I'm trying to do here is steer towards success by > pruning the problem to one that can be achieved without spending years > immersing yourself in specification. > Fair enough... I guess what I meant is that I'm surprised by the notion that this change would present a major problem in terms of updating the spec. The changes we want to make are clear (at least, they seem reasonably clear for this point in the process) so it's just a matter of articulating them precisely and unambiguously. Yes, I'm sure this will be tedious, but it shouldn't be overwhelmingly difficult. Heck if you point me at the JLS source code, I'll be happy to take a novice stab at it. For sure, all things being equal, a simpler language change means a simpler task updating the spec. But I'd still like to better understand how it might be possible to achieve the original goal. To that end, what are the problems with the plan outlined in the previous email? Similarly, you'll need a way to restate the "if it doesn't start with > `this/super`, you get an implicit super" to the more flexible notion being > outlined here. This is tricky because the obvious way to do this is to run > DA/DU on the explicit body of the constructor and ask if `this` is DA at > all points where the constructor could complete normally, and if not, > prepend a super() call and rerun DA/DU. This moves us from a strictly > syntactic rule to one that appeals to a complex analysis. > I'm not completely understanding this. Wouldn't it be simpler to just say that for any constructor in which this()/super() nowhere appears, the analysis starts with `this` being DA instead of DU? Or equivalently, the analysis proceeds as if super() were inserted as the first statement in the constructor. Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 20:19:30 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 15:19:30 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> Message-ID: <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> > I guess what I meant is that I'm surprised by the notion that this > change would present a major problem in terms of updating the spec. > The changes we want to make are clear (at least, they seem reasonably > clear for this point in the process) so it's just a matter of > articulating them precisely and unambiguously. Yes, I'm sure this will > be tedious, but it shouldn't be overwhelmingly difficult. Heck if you > point me at the JLS source code, I'll be happy to take a novice stab > at it. Nothing is impossible, of course.? But language changes are almost always more costly and impactful than initially assumed, especially when you've not been doing it for decades.? So guiding towards lower cost / lower risk, and asking "is the incremental benefit worth the incremental cost", is usually profitable. The PDFs of the spec are freely available; the sources are not easily accessible, since they are not open-sourced.? But you can work with the PDF text well enough; "replace the paragraph X with Y" should be good enough for an initial iteration. > To that end, what are the problems with the plan outlined in the > previous email? > > Similarly, you'll need a way to restate the "if it doesn't start > with `this/super`, you get an implicit super" to the more flexible > notion being outlined here.? This is tricky because the obvious > way to do this is to run DA/DU on the explicit body of the > constructor and ask if `this` is DA at all points where the > constructor could complete normally, and if not, prepend a super() > call and rerun DA/DU.? This moves us from a strictly syntactic > rule to one that appeals to a complex analysis. > > > I'm not completely understanding this. Wouldn't it be simpler to just > say that for any constructor in which this()/super() nowhere appears, > the analysis starts with `this` being DA instead of DU? Or > equivalently, the analysis proceeds as if super() were inserted as the > first statement in the constructor. For example, here's a constructor that contains a `this()` call, but for which `this` is not DA at the end: C() { ??? if (foo) ??????? this(3); } As it turns out, there's nothing we can do to save this constructor; we're going to error out due to flow issues.? But we have to do a fair amount of work before we can figure that out.? But the mere syntactic presence or absence of a super/this call is not obviously sufficient. The current rule about implicit supers is _syntactic_; we need only look at the parse tree and ask "was there an explicit super call", and know immediately whether we have to treat things as if there were a synthetic one, or not, before doing any analysis.? But a DA/DU-based rule means we have to speculatively perform linguistic analysis on the code (type checking, flow analysis, etc) to even determine whether this is really the code we want to work with in the first place, or whether we have to mangle it and then do it all again.? (Even this description is more a description of what the compiler will do; the spec doesn't talk about processing or type checking as a thing that happens, and so leans more heavily on things happening in a certain order in order for such analysis to be well-defined.) Additionally, since we currently quarantine the cases where `this` is DU to the single explicit constructor call, we don't have to thread DA of `this` throughout the rest of the JLS; the generalization would likely send tentacles farther and wider (e.g., lambda bodies, switch expressions, etc.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 25 21:09:23 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 25 Jan 2023 15:09:23 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 2:19 PM Brian Goetz wrote: > > I'm not completely understanding this. Wouldn't it be simpler to just say > that for any constructor in which this()/super() nowhere appears, the > analysis starts with `this` being DA instead of DU? Or equivalently, the > analysis proceeds as if super() were inserted as the first statement in the > constructor. > > > For example, here's a constructor that contains a `this()` call, but for > which `this` is not DA at the end: > > C() { > if (foo) > this(3); > } > > As it turns out, there's nothing we can do to save this constructor; we're > going to error out due to flow issues. But we have to do a fair amount of > work before we can figure that out. But the mere syntactic presence or > absence of a super/this call is not obviously sufficient. > > The current rule about implicit supers is _syntactic_; we need only look > at the parse tree and ask "was there an explicit super call", and know > immediately whether we have to treat things as if there were a synthetic > one, or not, before doing any analysis. But a DA/DU-based rule means we > have to speculatively perform linguistic analysis on the code (type > checking, flow analysis, etc) to even determine whether this is really the > code we want to work with in the first place, or whether we have to mangle > it and then do it all again. (Even this description is more a description > of what the compiler will do; the spec doesn't talk about processing or > type checking as a thing that happens, and so leans more heavily on things > happening in a certain order in order for such analysis to be > well-defined.) > I'm still not understanding (sorry). The new rule for implicit supers would be syntactic as well. The rule is this: Add an implicit super() if there are NO occurrences of any this() or a super() anywhere in the constructor. This is just the direct generalization of the previous version of this rule. If there is a this()/super() on some code branch but not on another, then do nothing. The DA/DU analysis will automatically catch the error. Additionally, since we currently quarantine the cases where `this` is DU to > the single explicit constructor call, we don't have to thread DA of `this` > throughout the rest of the JLS; the generalization would likely send > tentacles farther and wider (e.g., lambda bodies, switch expressions, > etc.) > This is where I'm proposing that we borrow from the concept of "static context". We'd say the "static context" rules apply to any statement in a constructor where 'this' is DU, with the exception of field assignment. This rule would just be an additional condition added on top of the existing rules. Wouldn't that work? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 21:23:56 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 16:23:56 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> Message-ID: <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> > I'm still not understanding (sorry). > > The new rule for implicit supers would be syntactic as well. > > The rule is this: Add an implicit super() if there are NO occurrences > of any this() or a super() anywhere in the constructor. So, let's look at the grammar.? Where does the production that matches `super(e)` come from?? Its from ConstructorBody: ??? ConstructorBody: ??? { [ExplicitConstructorInvocation] [BlockStatements] } If you pull on the string for BlockStatements, you'll see a whole nest of statement forms, *none of which match this(e) or super(e)*. So to allow one of these statements inside a block, you have to refactor all the statement productions in the language.? Then you have to go through the entire spec and prohibit these in the places where they can't be used (such as lambdas.) -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 25 21:41:41 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 25 Jan 2023 15:41:41 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 3:24 PM Brian Goetz wrote: > > I'm still not understanding (sorry). > > The new rule for implicit supers would be syntactic as well. > > The rule is this: Add an implicit super() if there are NO occurrences of > any this() or a super() anywhere in the constructor. > > > So, let's look at the grammar. Where does the production that matches > `super(e)` come from? Its from ConstructorBody: > > ConstructorBody: > { [ExplicitConstructorInvocation] [BlockStatements] } > > If you pull on the string for BlockStatements, you'll see a whole nest of > statement forms, *none of which match this(e) or super(e)*. So to allow > one of these statements inside a block, you have to refactor all the > statement productions in the language. Then you have to go through the > entire spec and prohibit these in the places where they can't be used (such > as lambdas.) > OK now I understand - thanks for being patient :) I didn't realize that the restriction that super()/this() must be first in a constructor was actually implemented using the language grammar. But it doesn't have to be that way, does it? I mean, the grammar allows "foobar()" to appear in any method, even when "foobar()" cannot be resolved. The requirement for "foobar()" to be resolvable is stated elsewhere, outside of the grammar. So why not, in the grammar, allow super()/this() to appear anywhere that any other method call can appear, and then layer on the restriction that they may only appear in constructors as a separate (English) sentence? It makes intuitive sense that we would need to do it this way because (as the JEP describes) we're converting a syntactic requirement into a semantic one. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Wed Jan 25 21:56:59 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Wed, 25 Jan 2023 16:56:59 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> Message-ID: <4422c133-8d18-d1f9-b822-1787cd3e74dc@oracle.com> > So, let's look at the grammar.? Where does the production that > matches `super(e)` come from?? Its from ConstructorBody: > > ??? ConstructorBody: > ??? { [ExplicitConstructorInvocation] [BlockStatements] } > > If you pull on the string for BlockStatements, you'll see a whole > nest of statement forms, *none of which match this(e) or > super(e)*.? So to allow one of these statements inside a block, > you have to refactor all the statement productions in the > language.? Then you have to go through the entire spec and > prohibit these in the places where they can't be used (such as > lambdas.) > > > OK now I understand - thanks for being patient :) > > I didn't realize that the restriction that super()/this() must be > first in a constructor was actually implemented using the language > grammar. > > But it doesn't have to be that way, does it? I mean, the grammar > allows "foobar()" to appear in any method, even when "foobar()" cannot > be resolved. The requirement for "foobar()" to be resolvable is stated > elsewhere, outside of the grammar. Specification is like programming in some ways.? There are many ways we could implement something.? Sometimes we prefer some ways because they are better than others; other times we prefer some ways because that's how we've been doing it for a long time and we've built up a large set of dependencies (some implicit) on that way of doing it. If you want to change a base assumption in a mature codebase, you should expect a higher effort, greater disruption, and more risk. It's the same way with spec, but probably more so. Justifying a feature like this is based on costs, risks, benefits, and priorities.? A feature with lower cost or risk is easier to justify.? Doing a 40% smaller feature (just going by your "3 out of 5" estimate) at 95% lower cost (making up a number here, but the difference appears significant) seems worth considering carefully. > So why not, in the grammar, allow super()/this() to appear anywhere > that any other method call can appear, and then layer on the > restriction that they may only appear in constructors as a separate > (English) sentence? That can be done, at a cost and at risk.? The cost is "how many places do you have to say this", and the risk is "what are the chances you've identified all of them."? If I can reduce this cost and risk to zero, that's attractive. > It makes intuitive sense that we would need to do it this way because > (as the JEP describes) we're converting a syntactic requirement into a > semantic one. But that's my point -- there's a simpler feature which feels like 90+% of the benefit that doesn't have this requirement.? The existing approach used here is quite clever -- and can be expanded a fair bit without having to make a wholesale change of direction. -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Wed Jan 25 23:06:31 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Wed, 25 Jan 2023 17:06:31 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <4422c133-8d18-d1f9-b822-1787cd3e74dc@oracle.com> References: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> <4422c133-8d18-d1f9-b822-1787cd3e74dc@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 3:57 PM Brian Goetz wrote: > > I didn't realize that the restriction that super()/this() must be first in > a constructor was actually implemented using the language grammar. > > But it doesn't have to be that way, does it? I mean, the grammar allows > "foobar()" to appear in any method, even when "foobar()" cannot be > resolved. The requirement for "foobar()" to be resolvable is stated > elsewhere, outside of the grammar. > > > Justifying a feature like this is based on costs, risks, benefits, and > priorities. A feature with lower cost or risk is easier to justify. Doing > a 40% smaller feature (just going by your "3 out of 5" estimate) at 95% > lower cost (making up a number here, but the difference appears > significant) seems worth considering carefully. > Gotcha. I think I need to spend time getting more familiar with the spec, so I can better understand how it's put together, what the trade-offs are, etc. Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Thu Jan 26 02:05:09 2023 From: john.r.rose at oracle.com (John Rose) Date: Wed, 25 Jan 2023 18:05:09 -0800 Subject: Loosening requirements for super() invocation In-Reply-To: References: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> <4422c133-8d18-d1f9-b822-1787cd3e74dc@oracle.com> Message-ID: On 25 Jan 2023, at 15:06, Archie Cobbs wrote: > On Wed, Jan 25, 2023 at 3:57 PM Brian Goetz > wrote: >> ? Doing >> a 40% smaller feature (just going by your "3 out of 5" estimate) at >> 95% >> lower cost (making up a number here, but the difference appears >> significant) seems worth considering carefully. > > Gotcha. I think I need to spend time getting more familiar with the > spec, > so I can better understand how it's put together, what the trade-offs > are, > etc. Brian is right; usually these sort of proposals break into layers, and in many cases the first 80% is where we stop. That said, I?d like to put on my DA/DU-expert hat for moment. (I invented the DU part of that analysis for blank finals in 1.1.) This analysis is subtle, understood by nearly nobody. For something that subtle, it delivers amazing value, because javac teaches the users what works and what doesn?t. The result is a very flexible language, and yet the danger areas (uninitialized values) are strongly fenced away from the user. I have always thought that the super() syntax restriction (the ?pinch point rule?) is a simple tactic to get the same job done as assigning DA/DU bits to ?this?. It?s a blunt instrument compared with the DA/DU analysis, and the spec. for it reads bluntly and simply. You?ll not be surprised that I am intrigued (though not convinced) about the alternative idea of leaning hard on new rules regarding DA/DU for ?this?. I?m pretty sure either tactic could be made to work in the JLS. I?m a little more hopeful than Brian that DA/DU bits would do the job well, but sometimes a sledgehammer is better than a samurai sword. What I?m wondering now is, if we use the sledgehammer technique, what is the total ?diff weight? of the spec.? Is it just a few touches or many? (It could be many, if various odd corner cases need special treatment, due to the bluntness of the instrument.) Likewise, if we carefully re-slice the DA/DU reasoning to cover ?this?, what would the total ?diff weight? be? I have an unrelated suggestion (which makes sense with either tactic). The existing DA/DU rules for blank finals are (I think) easy to adapt to allow blank finals initializations to be hoisted above super-init. So far so good. For non-finals (*mutable* non-static fields), may I suggest that, if you were to allow initializations to them above super-init, that you formulate the restrictions on their treatment to align them with blank finals. Something like this: - Before super-init, any *local* field, *without an initializer* (whether final or not) is put into the DU state. (Today it is blank finals only.) - Before super-init, no local fields may be read, and only DU fields may be written. (The JVM is slightly more lenient; we don?t care.) - Assignments to any field in a DU state put it into the DA state. (After that any further access must occur after super-init.) - Before super-init, the names `this.f` and `f`, where `f` means `this.f`, are treated identically, and there is no other expression which can be used to assign to `f`. (This is true for finals after super-init as well.) - Immediately after super-init, DA and DU bits are discarded for all non-final variables. This is also the place where field initializers and instance initializers are executed. - And of course, other than the above (special pleading for local blank fields), no uses of `this`, either explicit or implicit, are allowed. This may be because the code is textually before the pinch point, or else because ?this? is not DA until the super-init call. All this might be in the last 20%, beyond the good 80% we might well adopt. But I did want to put it out there. It is interesting to note that, given the restrictions on local fields in the ?early? code, there is almost no way to tell if the field assignments (the permitted early assignments to blank fields) are actually committed to the object, or are just stashed into locals. The only way you can tell if a field is actually committed is for an unusual things to happen. The super-init method has to turn around and access that field, either directly (via a cast), or (more likely) via an instance method with an override in the subclass (which makes a secret cast during virtual dispatch). This is rare but non-unheard-of, and uplevel links of inner classes are sometimes used this way, by super-init calls to virtuals. I think it would be good (if possible) to give this tool to source programmers, and not just to hardwired inner-class links. One more point: This use case could supported in either way: Either eagerly write assigned field values at the assignment point, or stash them in locals, and commit them all just before the super-init call, which is where the possibility of observing the fields begins. This leads me to one more observation: Blank finals can be observed in their uninitialized state during a super-init call. This is a hole in the otherwise strong fence around final variables, and it sometimes causes bad bugs. It will make the fence around finals stronger if we allow them to be initialized before the super-init call. That is, if users take the chance of initializing their blank finals before the super-init call, then there is a very strong proof that no such blank final will ever be observed in its uninitialized state. To me that?s an indication that we should put this feature in the 80% rather than the 20%. The blank non-finals can come along for the ride also, maybe, or maybe they belong in the 20% remainder. If that?s the case, some of my suggestions above (but not all) are still relevant. -------------- next part -------------- An HTML attachment was scrubbed... URL: From angelos.bimpoudis at oracle.com Thu Jan 26 09:48:47 2023 From: angelos.bimpoudis at oracle.com (Angelos Bimpoudis) Date: Thu, 26 Jan 2023 09:48:47 +0000 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch Message-ID: Hello all, I would like to share this draft JEP with you about primitive types in patterns, instanceof, and switch: https://openjdk.org/jeps/8288476 "Enhance pattern matching by allowing primitive types to appear anywhere in patterns. Extend instanceof to support primitive types, and extend switch to allow primitive constants as case labels." Comments very much welcomed! Many thanks, Angelos -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Thu Jan 26 13:15:16 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Thu, 26 Jan 2023 14:15:16 +0100 (CET) Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> > From: "Angelos Bimpoudis" > To: "amber-dev" > Sent: Thursday, January 26, 2023 10:48:47 AM > Subject: Draft JEP on Primitive types in patterns, instanceof, and switch > Hello all, > I would like to share this draft JEP with you about primitive types in patterns, > instanceof, and switch: > https://openjdk.org/jeps/8288476 > "Enhance pattern matching by allowing primitive types to appear anywhere in > patterns. Extend instanceof to support primitive types, and extend switch to > allow primitive constants as case labels." > Comments very much welcomed! > Many thanks, > Angelos I still think that the semantics proposed for pattern matching on primitive types is useless complexity with the perverse side effect of normalizing the usage of "default" in pattern matching (too many examples of this JEP are using "default") but we already discussed that. Allowing switching on double and float constants is just wrong. Rust is actually trying to remove that feature [ https://github.com/rust-lang/rust/issues/41255 | https://github.com/rust-lang/rust/issues/41255 ] I see no point to make the same mistake. Otherwise, the rest is fine. R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Jan 26 14:55:23 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Jan 2023 14:55:23 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> Message-ID: <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Hi Archie, the JEP is very well written, good job. I have been bitten in the past by the problems you describe in the JEP, so I'm very sympathetic with this work. The examples you have included do a very good job at describing the "limitations" that we have all gotten (too?) used to. Being able to dynamically decide which superclass constructor to call is very powerful, and the examples you have with complex initialization are very shiny (in a good way :-) ). One example that I didn't get was the NullPointer vs. IAE - to me this seems another case where you want to validate the parameter before passing it to the superclass constructor - e.g. the same as the very first example. For this reason, this example seems weak to me - and the JEP would probably be better off with it omitted (unless I missed some more subtle point, which is possible). As stated in the goals of the JEP, your aim is to align the JLS with what the JVMS allows - which is generally a good and noble starting point. That said, I find that the JEP goes perhaps a little too far in that direction, especially when it shows allowing initialization of instance fields _before_ the superclass constructor is called. I understand that this does not violate the top-down principle, and that the JVMS caters for it, but seeing that in a program seems odd, and all sort of questions started popping up in the back of my mind - e.g. what if the class initialized a protected field in the superclass before the superclass constructor is called? And, the fact that depending on whether field initialization is done before or after super leads to different error messages (as you show in the JEP) seems also potentially surprising. My feeling is that it would be better to start simple(r), and, at least for the time being, not to give instance field initializers any special treatment. That is, if you refer to `this` before the superclass constructor has been called, even to set a field, you get an error. I don't think we would lose too much: as your examples show, there's quite a lot of "obviously correct" stuff that this JEP would allow, even w/o descending into more questionable territory (e.g. instance field initialization). In fact, the only example that would benefit from assigning fields before the superclass constructor call, is a "bad" case of escaping this - not sure how much it's worth doing to support this TBH. Cheers Maurizio On 20/01/2023 17:37, Archie Cobbs wrote: > On Wed, Jan 11, 2023 at 10:27 AM Vicente Romero > wrote: > > >> For the code before super() work (JDK-8194743 >> ), is it OK to file >> a PR before there is a JEP? > > it could be done either way but I think that going for the JEP > first is usually a better approach > > > OK, JEP filed here: https://bugs.openjdk.org/browse/JDK-8300786 > > Fire away :) > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 16:12:19 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 10:12:19 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: Hi Maurizio, Thanks very much for taking time to review. On Thu, Jan 26, 2023 at 8:55 AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > One example that I didn't get was the NullPointer vs. IAE - to me this > seems another case where you want to validate the parameter before passing > it to the superclass constructor - e.g. the same as the very first example. > For this reason, this example seems weak to me - and the JEP would probably > be better off with it omitted (unless I missed some more subtle point, > which is possible). > Yes... I also thought maybe we should combine those two examples into one. You've confirmed the hunch so I'll make that change. what if the class initialized a protected field in the superclass before > the superclass constructor is called? > That possibility may seem "weird" because it's a new possibility for the first time in 25+ years, but I'd argue that with a little analysis it turns out it doesn't actually lead to any problematic or surprising outcome. One could also argue that the language already allows much weirder things, like 'this' escapes where a subclass can observe a supposedly final field with the wrong value... Anyway, here's a breakdown of what happens if a subclass writes to a superclass field prior to super(): If the superclass field is final, assignment is not allowed - you get the usual "cannot assign a value to final variable x" (no change here). Otherwise, before super() is invoked, the field may not be read, and invocation of superclass methods are disallowed, so the field's value can have no effect on anything. When super() is invoked, either the superclass constructor overwrites the value or it doesn't (if it reads the value, then presumably that's intentional). If the superclass constructor overwrites the value, the field gets its new value, as expected. If the superclass constructor doesn't overwrite the value, the field retains the value written by the subclass, as expected. So in a nutshell, it behaves as one would expect: either the superclass constructor overwrites the value, or it doesn't. Life goes on. (And if you don't like subclass constructors writing to your fields prior to super(), you can make them private or final, or just overwrite them in your constructor.) So yes this scenario is new and different, but I don't think it's fair to say it's problematic. It's just new. My feeling is that it would be better to start simple(r), and, at least for > the time being, not to give instance field initializers any special > treatment. > Certainly agree it would be simpler... but it would be at the cost of eliminating the only tool we'll likely ever have for dealing with a superclass 'this' escape, which is one of the primary motivations behind this change. But back to the crux... if what you're saying is that you're worried about the uncertainty around initializing fields prior to super(), does the earlier breakdown showing that it's harmless (so to speak) help any? Thanks, -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 26 16:59:41 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 26 Jan 2023 11:59:41 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: What we're seeing here is something that happens all the time -- we start with a notion of "hey, it would be great to improve the language in X way", and then, as we start to write down specifics, realize that there might be a better design center. We got here by observing "gee, the VM is much more tolerant than the language here, maybe we should align the language to the VM", along with some obvious examples of code we can't write today that we'd like to be able to write. As we look at the implications of this, though, we start to see that the cost/risk/complexity keeps cropping up in the lower-value aspects.? To summarize, here are the things you originally proposed to align: ?- Allowing statements before the this/super; ?- Choosing different super/this ctors in different paths; ?- Initializing fields prior to this being DA. I think we can agree that the first bullet subsumes most of the pain that users are in; it addresses things like "putting logic where it belongs", allowing the same computed value to be used multiple times without recomputing it, etc.? The second feels fairly niche, and while I can certainly imagine occasionally wanting it, is probably 100x less common than the first, and is where the vast majority of new spec complexity would come from. The third seems a workaround for classes that are already kind of broken with respect to this-escape, and I'm not sure we win by encouraging this (since there's still an escaping `this`.) So it feels to me that the emerging consolidated design center is "statements before this/super".? The spec impact is quite small and compact, and the expressiveness impact is pretty significant.? I think rallying around this consolidated center will result in a better chance of success, and a stronger payoff. On 1/26/2023 11:12 AM, Archie Cobbs wrote: > Hi Maurizio, > > Thanks very much for taking time to review. > > On Thu, Jan 26, 2023 at 8:55 AM Maurizio Cimadamore > wrote: > > One example that I didn't get was the NullPointer vs. IAE - to me > this seems another case where you want to validate the parameter > before passing it to the superclass constructor - e.g. the same as > the very first example. For this reason, this example seems weak > to me - and the JEP would probably be better off with it omitted > (unless I missed some more subtle point, which is possible). > > > Yes... I also thought maybe we should combine those two examples into > one. You've confirmed the hunch so I'll make that change. > > what if the class initialized a protected field in the superclass > before the superclass constructor is called? > > > That possibility may seem "weird" because it's a new possibility for > the first time in 25+ years, but I'd argue that with a little analysis > it turns out it doesn't actually lead to any problematic or surprising > outcome. > > One could also argue that the language already allows much weirder > things, like 'this' escapes where a subclass can observe a supposedly > final field with the wrong value... > > Anyway, here's a breakdown of what happens if a subclass writes to a > superclass field prior to super(): > > If the superclass field is final, assignment is not allowed - you get > the usual "cannot assign a value to final variable x" (no change here). > > Otherwise, before super() is invoked, the field may not be read, and > invocation of superclass methods are disallowed, so the field's value > can have no effect on anything. > > When super() is invoked, either the superclass constructor overwrites > the value or it doesn't (if it reads the value, then presumably that's > intentional). > > If the superclass constructor overwrites the value, the field gets its > new value, as expected. > > If the superclass constructor doesn't overwrite the value, the field > retains the value written by the subclass, as expected. > > So in a nutshell, it behaves as one would expect: either the > superclass constructor overwrites the value, or it doesn't. Life goes on. > > (And if you don't like subclass constructors writing to your fields > prior to super(), you can make them private or final, or just > overwrite them in your constructor.) > > So yes this scenario is new and different, but I don't think it's fair > to say it's problematic. It's just new. > > My feeling is that it would be better to start simple(r), and, at > least for the time being, not to give instance field initializers > any special treatment. > > > Certainly agree it would be simpler... but it would be at the cost of > eliminating the only tool we'll likely ever have for dealing with a > superclass 'this' escape, which is one of the primary motivations > behind this change. > > But back to the crux... if what you're saying is that you're worried > about the uncertainty around initializing fields prior to super(), > does the earlier breakdown showing that it's harmless (so to speak) > help any? > > Thanks, > -Archie > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Jan 26 17:00:15 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Jan 2023 17:00:15 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: On 26/01/2023 16:12, Archie Cobbs wrote: > Hi Maurizio, > > Thanks very much for taking time to review. > > On Thu, Jan 26, 2023 at 8:55 AM Maurizio Cimadamore > wrote: > > One example that I didn't get was the NullPointer vs. IAE - to me > this seems another case where you want to validate the parameter > before passing it to the superclass constructor - e.g. the same as > the very first example. For this reason, this example seems weak > to me - and the JEP would probably be better off with it omitted > (unless I missed some more subtle point, which is possible). > > > Yes... I also thought maybe we should combine those two examples into > one. You've confirmed the hunch so I'll make that change. Thanks > > what if the class initialized a protected field in the superclass > before the superclass constructor is called? > > > That possibility may seem "weird" because it's a new possibility for > the first time in 25+ years, but I'd argue that with a little analysis > it turns out it doesn't actually lead to any problematic or surprising > outcome. > I agree that the behavior you propose is not problematic per se. But, as I mentioned, it brings up can of worms. For instance, now a superclass constructor could see its field with a non-zero value. Which could definitively be surprising. After all, there might be code in the wild assuming that an int field that has not been assigned yet has value zero - whether writing code like that is good or bad, it's a separate question. My point here is that here you cross a fine line between? "let's make the language more expressive" and "this change might have some compatibility impact". As I said, my general feeling is that it's not worth going there to "fix escaping this" - because... developers should strive to write code where this doesn't escape in the first place (and hopefully the Lint warning you recently added will help with that). Maurizio > Thanks, > -Archie > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 17:05:22 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 11:05:22 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <3b6440d9-1b2b-c10b-a07b-e0ad8cc4aa66@oracle.com> <8ac4afe5-3e70-324d-6ce9-2609f7e6b83c@oracle.com> <5bb5403b-25b5-bf1e-8d74-d91db89da0c6@oracle.com> <82186af9-cf33-a363-8c87-08eb2401a457@oracle.com> <0eb44494-374e-6d4d-9476-e1c6e496ee63@oracle.com> <4422c133-8d18-d1f9-b822-1787cd3e74dc@oracle.com> Message-ID: On Wed, Jan 25, 2023 at 8:05 PM John Rose wrote: > I?m pretty sure either tactic could be made to work in the JLS. I?m a > little more hopeful than Brian that DA/DU bits would do the job well, but > sometimes a sledgehammer is better than a samurai sword. What I?m wondering > now is, if we use the sledgehammer technique, what is the total ?diff > weight? of the spec.? > That's a question I'd like to better understand as well. Brian pointed out the commonality between code and spec - both are going to require some refactoring when a change is made... i.e., we can't just add a footnote that says, "Oh and one more thing: everything we just said is true except that code prior to super() ..." So the question is mostly about how much refactoring will be required, as the refactoring is likely to be most of the "diff weight". It's still an open question in my mind but also I need to do more study. Brian has a definite opinion here and he's probably right but I want to confirm that for myself... > I have an unrelated suggestion (which makes sense with either tactic). The > existing DA/DU rules for blank finals are (I think) easy to adapt to allow > blank finals initializations to be hoisted above super-init. So far so > good. For non-finals (*mutable* non-static fields), may I suggest that, > if you were to allow initializations to them above super-init, that you > formulate the restrictions on their treatment to align them with blank > finals. Something like this: > > - > > Before super-init, any *local* field, *without an initializer* > (whether final or not) is put into the DU state. (Today it is blank finals > only.) > - > > Before super-init, no local fields may be read, and only DU fields may > be written. (The JVM is slightly more lenient; we don?t care.) > - > > Assignments to any field in a DU state put it into the DA state. > (After that any further access must occur after super-init.) > > So if I understand what you're getting at, you're saying "Prior to super(), if you assign a value to a non-final field, we're going to treat it as if the field were actually final". But I don't understand what that buys us compared to just leaving the rules for non-final fields alone (I'm sure I'm missing something). So what if you can assign them more than once? No harm there. And developers may scratch their heads if this code: public class Foo { private int ival; public Foo(float fval) { this.ival = (int)fval; if (!Float.isFinite(fval)) this.ival = -1; super(); } } generates an error like this: Foo.java:8 error: variable ival may have already been assigned this.ival = -1; ^ > > - Before super-init, the names this.f and f, where f means this.f, are > treated identically, and there is no other expression which can be used to > assign to f. (This is true for finals after super-init as well.) > > Yes, something limited like this would be needed. We already have the same limitation when assigning final fields - as you describe in JDK-8193904 . > This leads me to one more observation: Blank finals can be observed in > their uninitialized state during a super-init call. This is a hole in the > otherwise strong fence around final variables, and it sometimes causes bad > bugs. It will make the fence around finals stronger if we allow them to be > initialized before the super-init call. That is, if users take the chance > of initializing their blank finals before the super-init call, then there > is a very strong proof that no such blank final will ever be observed in > its uninitialized state. To me that?s an indication that we should put this > feature in the 80% rather than the 20%. > I totally agree... you said it much better than me. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 17:13:36 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 11:13:36 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 10:59 AM Brian Goetz wrote: > As we look at the implications of this, though, we start to see that the > cost/risk/complexity keeps cropping up in the lower-value aspects. To > summarize, here are the things you originally proposed to align: > > - Allowing statements before the this/super; > - Choosing different super/this ctors in different paths; > - Initializing fields prior to this being DA. > I think we all agree on #1. I agree that #2 is "niche" and therefore should be included ONLY if it's not the singular cause of a bunch of additional spec noise. Personally I "believe" you (air quotes) that it would be, but also want to see for myself... I'm sure you'll be proved right... and for now will leave that to others to argue. Seems like there's still some valid debate (not just from me) about #3 though... ? -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 26 17:25:37 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 26 Jan 2023 12:25:37 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: <7e647644-dc38-cdb7-8eab-f8d7c9f215ea@oracle.com> So, its possible that #3 also has reasonable cost/benefit.? The current "pinch point" approach could probably be brought to bear on it with modifications, without having to thread everything through DA.? But I think there are subtleties to think through first. For example, would this be allowed? class A { ??? final int a; ??? A() { this.a = 0; } } class B extends A { ??? B() { ??????? this.a = 1; ??????? super(); ??? } } The current draft JEP says it would: > Add the following restrictions on constructors: > ??? No access to this, other than assignments to fields, may occur > unless this is DA This is clearly an "assignment to a field", but I think we can agree that the code above is pretty dodgy. So what I'm proposing is to address the feature that everyone likes and we agree can be addressed with less fuss, and then consider coming back for more later. On 1/26/2023 12:13 PM, Archie Cobbs wrote: > On Thu, Jan 26, 2023 at 10:59 AM Brian Goetz > wrote: > > As we look at the implications of this, though, we start to see > that the cost/risk/complexity keeps cropping up in the lower-value > aspects.? To summarize, here are the things you originally > proposed to align: > > ?- Allowing statements before the this/super; > ?- Choosing different super/this ctors in different paths; > ?- Initializing fields prior to this being DA. > > > I think we all agree on #1. > > I agree that #2 is "niche" and therefore should be included ONLY if > it's not the singular cause of a bunch of additional spec noise. > Personally I "believe" you (air quotes) that it would be, but also > want to see for myself... I'm sure you'll be proved right...? and for > now will leave that to others to argue. > > Seems like there's still some valid debate (not just from me) about #3 > though... ? > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From per-ake.minborg at oracle.com Thu Jan 26 17:26:47 2023 From: per-ake.minborg at oracle.com (Per-Ake Minborg) Date: Thu, 26 Jan 2023 17:26:47 +0000 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: Maybe certain values for float and double should be allowable (e.g. NaN (matching all variants), POSITIVE_INFINITY, NEGATIVE_INFINITY and zero (matching any zero value))? These are clearly defined. All other values would render a compile-time error? (many question marks here) /P ________________________________ From: amber-dev on behalf of Remi Forax Sent: Thursday, January 26, 2023 2:15 PM To: Angelos Bimpoudis Cc: amber-dev Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch ________________________________ From: "Angelos Bimpoudis" To: "amber-dev" Sent: Thursday, January 26, 2023 10:48:47 AM Subject: Draft JEP on Primitive types in patterns, instanceof, and switch Hello all, I would like to share this draft JEP with you about primitive types in patterns, instanceof, and switch: https://openjdk.org/jeps/8288476 "Enhance pattern matching by allowing primitive types to appear anywhere in patterns. Extend instanceof to support primitive types, and extend switch to allow primitive constants as case labels." Comments very much welcomed! Many thanks, Angelos I still think that the semantics proposed for pattern matching on primitive types is useless complexity with the perverse side effect of normalizing the usage of "default" in pattern matching (too many examples of this JEP are using "default") but we already discussed that. Allowing switching on double and float constants is just wrong. Rust is actually trying to remove that feature https://github.com/rust-lang/rust/issues/41255 I see no point to make the same mistake. Otherwise, the rest is fine. R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 18:07:09 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 12:07:09 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <7e647644-dc38-cdb7-8eab-f8d7c9f215ea@oracle.com> References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <7e647644-dc38-cdb7-8eab-f8d7c9f215ea@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 11:25 AM Brian Goetz wrote: > For example, would this be allowed? > > class A { > final int a; > > A() { this.a = 0; } > } > > class B extends A { > B() { > this.a = 1; > super(); > } > } > No, that's definitely not supposed to be allowed. > The current draft JEP says it would: > > Add the following restrictions on constructors: > No access to this, other than assignments to fields, may occur unless > this is DA > > Thanks for pointing that out. I've updated the draft to say "other than assignments to local fields". So, its possible that #3 also has reasonable cost/benefit. The current > "pinch point" approach could probably be brought to bear on it with > modifications, without having to thread everything through DA. But I think > there are subtleties to think through first. > I'm hopeful we can include #3 - I think it's important because it gives users a way to address a problem that is all at once subtle, dangerous, and difficult to avoid. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 18:16:43 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 12:16:43 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <91E15764-ECBF-43DB-831F-0FB31CD0ECE9@oracle.com> <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 11:00 AM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > I agree that the behavior you propose is not problematic per se. > > But, as I mentioned, it brings up can of worms. For instance, now a > superclass constructor could see its field with a non-zero value. Which > could definitively be surprising. After all, there might be code in the > wild assuming that an int field that has not been assigned yet has value > zero - whether writing code like that is good or bad, it's a separate > question. My point here is that here you cross a fine line between "let's > make the language more expressive" and "this change might have some > compatibility impact". > Yes, but for this to happen the subclass would have to be in effect intentionally subverting the superclass constructor. In other words, a problem like you describe can't suddenly just start happening "by accident" just because this new feature exists... As I said, my general feeling is that it's not worth going there to "fix > escaping this" - because... developers should strive to write code where > this doesn't escape in the first place (and hopefully the Lint warning you > recently added will help with that). > That horse has already left the barn... for example a bunch of JDK classes like HashSet. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 18:52:14 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 12:52:14 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <7e647644-dc38-cdb7-8eab-f8d7c9f215ea@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 12:07 PM Archie Cobbs wrote: > > Add the following restrictions on constructors: >> No access to this, other than assignments to fields, may occur unless >> this is DA >> >> > Thanks for pointing that out. I've updated the draft to say "other than > assignments to local fields". > I just realized that this wording change nicely avoids the "weirdness" problem of writing to non-final superclass fields before super(). That seems like a good thing based on the earlier discussion. Another instance where the JVMS would allow something, but that doesn't necessarily mean it's a good idea in the language. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Jan 26 19:19:14 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Jan 2023 19:19:14 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: On 26/01/2023 18:16, Archie Cobbs wrote: > On Thu, Jan 26, 2023 at 11:00 AM Maurizio Cimadamore > wrote: > > I agree that the behavior you propose is not problematic per se. > > But, as I mentioned, it brings up can of worms. For instance, now > a superclass constructor could see its field with a non-zero > value. Which could definitively be surprising. After all, there > might be code in the wild assuming that an int field that has not > been assigned yet has value zero - whether writing code like that > is good or bad, it's a separate question. My point here is that > here you cross a fine line between? "let's make the language more > expressive" and "this change might have some compatibility impact". > > Yes, but for this to happen the subclass would have to be in effect > intentionally subverting the superclass constructor. > > In other words, a problem like you describe can't suddenly just start > happening "by accident" just because this new feature exists... Well, you could have a subclass (in some client jar) which "subverts" as you say, some superclass in a library. Perhaps the library was not prepared for that kind of behavior, and now there's a new bug. IMHO, we should try to stay well clear of that can of worms. It's not like we have to open it now either - the other things you propose are 100% non-controversial. Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 19:22:12 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 13:22:12 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 1:19 PM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > On 26/01/2023 18:16, Archie Cobbs wrote: > > On Thu, Jan 26, 2023 at 11:00 AM Maurizio Cimadamore < > maurizio.cimadamore at oracle.com> wrote: > >> I agree that the behavior you propose is not problematic per se. >> >> But, as I mentioned, it brings up can of worms. For instance, now a >> superclass constructor could see its field with a non-zero value. Which >> could definitively be surprising. After all, there might be code in the >> wild assuming that an int field that has not been assigned yet has value >> zero - whether writing code like that is good or bad, it's a separate >> question. My point here is that here you cross a fine line between "let's >> make the language more expressive" and "this change might have some >> compatibility impact". >> > Yes, but for this to happen the subclass would have to be in effect > intentionally subverting the superclass constructor. > > In other words, a problem like you describe can't suddenly just start > happening "by accident" just because this new feature exists... > > Well, you could have a subclass (in some client jar) which "subverts" as > you say, some superclass in a library. Perhaps the library was not prepared > for that kind of behavior, and now there's a new bug. > > IMHO, we should try to stay well clear of that can of worms. It's not like > we have to open it now either - the other things you propose are 100% > non-controversial. > So what do you think then of only allowing access to *local* fields prior to super()? Seems like this draws the boundary more tightly around the functionality we're actually aiming for, and keeps out the wormy stuff. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Thu Jan 26 20:54:47 2023 From: kevinb at google.com (Kevin Bourrillion) Date: Thu, 26 Jan 2023 12:54:47 -0800 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: Depending on float equality is *dangerous*, but doesn't completely lack valid use cases. Doing so in this manner doesn't seem fundamentally different from all the other ways you can do it too; in my world, *any* of these ways will earn you a static analysis warning. The user can suppress that, and I think this is a wholly reasonable arrangement. On Thu, Jan 26, 2023 at 9:26 AM Per-Ake Minborg wrote: > Maybe certain values for float and double should be allowable (e.g. NaN > (matching all variants), POSITIVE_INFINITY, NEGATIVE_INFINITY and zero > (matching any zero value))? These are clearly defined. All other values > would render a compile-time error? (many question marks here) /P > ------------------------------ > *From:* amber-dev on behalf of Remi Forax < > forax at univ-mlv.fr> > *Sent:* Thursday, January 26, 2023 2:15 PM > *To:* Angelos Bimpoudis > *Cc:* amber-dev > *Subject:* Re: Draft JEP on Primitive types in patterns, instanceof, and > switch > > > > ------------------------------ > > *From: *"Angelos Bimpoudis" > *To: *"amber-dev" > *Sent: *Thursday, January 26, 2023 10:48:47 AM > *Subject: *Draft JEP on Primitive types in patterns, instanceof, and > switch > > Hello all, > > I would like to share this draft JEP with you about primitive types in > patterns, instanceof, and switch: > > https://openjdk.org/jeps/8288476 > > "Enhance pattern matching by allowing primitive types to appear anywhere > in patterns. Extend instanceof to support primitive types, and extend > switch to allow primitive constants as case labels." > > Comments very much welcomed! > > Many thanks, > Angelos > > > I still think that the semantics proposed for pattern matching on > primitive types is useless complexity with the perverse side effect of > normalizing the usage of "default" in pattern matching (too many examples > of this JEP are using "default") but we already discussed that. > > Allowing switching on double and float constants is just wrong. > Rust is actually trying to remove that feature > https://github.com/rust-lang/rust/issues/41255 > > I see no point to make the same mistake. > > Otherwise, the rest is fine. > > R?mi > > -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From pedro.lamarao at prodist.com.br Thu Jan 26 21:09:43 2023 From: pedro.lamarao at prodist.com.br (=?UTF-8?Q?Pedro_Lamar=C3=A3o?=) Date: Thu, 26 Jan 2023 18:09:43 -0300 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: Em qui., 26 de jan. de 2023 ?s 17:55, Kevin Bourrillion escreveu: > Depending on float equality is *dangerous*, but doesn't completely lack > valid use cases. > With some kind of epsilon predicate, this should become more useful. -- Pedro Lamar?o -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Thu Jan 26 21:19:09 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Thu, 26 Jan 2023 22:19:09 +0100 (CET) Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: <1347020225.6189991.1674767949665.JavaMail.zimbra@u-pem.fr> > From: "Kevin Bourrillion" > To: "Per-Ake Minborg" > Cc: "Remi Forax" , "Angelos Bimpoudis" > , "amber-dev" > Sent: Thursday, January 26, 2023 9:54:47 PM > Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch > Depending on float equality is *dangerous*, but doesn't completely lack valid > use cases. > Doing so in this manner doesn't seem fundamentally different from all the other > ways you can do it too; in my world, *any* of these ways will earn you a static > analysis warning. The user can suppress that, and I think this is a wholly > reasonable arrangement. I agree apart on the idea of having to rely on a static analysis tool. I still remember the time before Java 1.5 where there was no warning. I would prefer a feature just released to not require a new static analysis. Anyway, that does not solve the issue raised by Guy, can case 0.0 and case -0.0 be both present in a same switch ? R?mi > On Thu, Jan 26, 2023 at 9:26 AM Per-Ake Minborg < [ > mailto:per-ake.minborg at oracle.com | per-ake.minborg at oracle.com ] > wrote: >> Maybe certain values for float and double should be allowable (e.g. NaN >> (matching all variants), POSITIVE_INFINITY, NEGATIVE_INFINITY and zero >> (matching any zero value))? These are clearly defined. All other values would >> render a compile-time error? (many question marks here) /P >> From: amber-dev < [ mailto:amber-dev-retn at openjdk.org | >> amber-dev-retn at openjdk.org ] > on behalf of Remi Forax < [ >> mailto:forax at univ-mlv.fr | forax at univ-mlv.fr ] > >> Sent: Thursday, January 26, 2023 2:15 PM >> To: Angelos Bimpoudis < [ mailto:angelos.bimpoudis at oracle.com | >> angelos.bimpoudis at oracle.com ] > >> Cc: amber-dev < [ mailto:amber-dev at openjdk.org | amber-dev at openjdk.org ] > >> Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch >>> From: "Angelos Bimpoudis" < [ mailto:angelos.bimpoudis at oracle.com | >>> angelos.bimpoudis at oracle.com ] > >>> To: "amber-dev" < [ mailto:amber-dev at openjdk.org | amber-dev at openjdk.org ] > >>> Sent: Thursday, January 26, 2023 10:48:47 AM >>> Subject: Draft JEP on Primitive types in patterns, instanceof, and switch >>> Hello all, >>> I would like to share this draft JEP with you about primitive types in patterns, >>> instanceof, and switch: >>> [ https://openjdk.org/jeps/8288476 | https://openjdk.org/jeps/8288476 ] >>> "Enhance pattern matching by allowing primitive types to appear anywhere in >>> patterns. Extend instanceof to support primitive types, and extend switch to >>> allow primitive constants as case labels." >>> Comments very much welcomed! >>> Many thanks, >>> Angelos >> I still think that the semantics proposed for pattern matching on primitive >> types is useless complexity with the perverse side effect of normalizing the >> usage of "default" in pattern matching (too many examples of this JEP are using >> "default") but we already discussed that. >> Allowing switching on double and float constants is just wrong. >> Rust is actually trying to remove that feature >> [ https://github.com/rust-lang/rust/issues/41255 | >> https://github.com/rust-lang/rust/issues/41255 ] >> I see no point to make the same mistake. >> Otherwise, the rest is fine. >> R?mi > -- > Kevin Bourrillion | Java Librarian | Google, Inc. | [ mailto:kevinb at google.com | > kevinb at google.com ] -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Thu Jan 26 21:34:08 2023 From: kevinb at google.com (Kevin Bourrillion) Date: Thu, 26 Jan 2023 13:34:08 -0800 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: On Thu, Jan 26, 2023 at 1:09 PM Pedro Lamar?o wrote: Depending on float equality is *dangerous*, but doesn't completely lack >> valid use cases. >> > > With some kind of epsilon predicate, this should become more useful. > Sometimes, but intransitive "equivalence" is one problem traded for another. -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From forax at univ-mlv.fr Thu Jan 26 21:37:12 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Thu, 26 Jan 2023 22:37:12 +0100 (CET) Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: <406495156.6191469.1674769032681.JavaMail.zimbra@u-pem.fr> > From: "Pedro Lamar?o" > To: "Kevin Bourrillion" > Cc: "Per-Ake Minborg" , "Remi Forax" > , "Angelos Bimpoudis" , > "amber-dev" > Sent: Thursday, January 26, 2023 10:09:43 PM > Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch > Em qui., 26 de jan. de 2023 ?s 17:55, Kevin Bourrillion < [ > mailto:kevinb at google.com | kevinb at google.com ] > escreveu: >> Depending on float equality is *dangerous*, but doesn't completely lack valid >> use cases. > With some kind of epsilon predicate, this should become more useful. I think you will have to wait for the introduction of named patterns for this one, something like case Double.around(10.0, EPSILON)(double d) -> ... With the mention that this is obviously not the real syntax but a snippet of code to help to drive the discussion. > -- > Pedro Lamar?o regards, R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Jan 26 21:37:23 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Jan 2023 21:37:23 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: <039c67d7-a622-29db-570c-54e306585908@oracle.com> On 26/01/2023 19:22, Archie Cobbs wrote: > So what do you think then of only allowing access to /local/ fields > prior to super()? By local fields I assume you mean "fields defined in the same class as constructor". I doesn't change my opinion much, if I'm being honest. I'm skeptical of anything that can affect the observable initialization order of fields in a class. For instance, even if we only allow updates to local fields, an instance initializer can now see these updates. for you, this is something good, for me this is just something else that developers would have to remember about initialization order. Is it terrible? Probably not. Do we really need to go there? Probably not, either :-) Maurizio -------------- next part -------------- An HTML attachment was scrubbed... URL: From scolebourne at joda.org Thu Jan 26 22:01:10 2023 From: scolebourne at joda.org (Stephen Colebourne) Date: Thu, 26 Jan 2023 22:01:10 +0000 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: "On Thu, 26 Jan 2023 at 09:49, Angelos Bimpoudis wrote: > I would like to share this draft JEP with you about primitive types in patterns, instanceof, and switch: > > https://openjdk.org/jeps/8288476 > > "Enhance pattern matching by allowing primitive types to appear anywhere in patterns. Extend instanceof to support primitive types, and extend switch to allow primitive constants as case labels." > > Comments very much welcomed! I am implacably opposed to this JEP. I think it breaks a fundamental tenet of the Java language, and it will result in code that is difficult to read and reason about. A large part of the Goals and Motivation section are focussed on the question of how to check and convert from `int` to `byte` or similar. At no point does the document acknowledge that such conversions are rare. This isn't a problem people are crying out to be fixed. Instead, this JEP is merely an attempt to justify utterly nonsensical behaviour that breaks decades of language principles. Specifically, the Goal "Provide easy-to-use constructs that eliminate the risk of losing information due to unsafe casts" does *not* need to be met by a change to the *language*. Checking whether an `int` can be converted to a `byte` is indeed a perfectly reasonable question, but it should be a library method, not a language feature. In the Motivation section it is claimed that because `byte b = 42` compiles, it implies that sometimes an `int` can be converted to a `byte` without a cast. This is nonsense. In this context, `42` is *not* an `int` at all - it is a literal. There is no conversion here, `42` is typed as a `byte` because of the assignment. `42` is never, at any stage, an `int`. At the very least, the JEP should be amended to remove this part of the Motivation section. The document proceeds to argue that because switch works with Object hierarchies: Pet p = new Pet(new Dog()); // automatic widening conversion from Dog to Animal switch (p) { case Pet(Dog d) -> ... d ... case Pet(Animal a) -> ... a ... default -> ... } that it must therefore be OK to work with primitives: int i = methodReturningShort(); switch (i) { case byte b -> ... b ...; case float f -> ... f ...; default -> -1; } There is simply no comparison here. Dog and Animal are subtypes of Pet, a concept that has been baked into the language since day one, and is fully understood by all. By contrast, there is absolutely no subtyping relationship between int, byte and short, and again this fact has been baked into the language since day one. There is a *huge* red line being crossed here. Values in Java have two distinct parts - the type and the value of the instance. Java has always kept these two things completely separate: General-purpose language features operate on types and references/null (eg. instanceof, catch, switch) or expressions (if, for, while). It requires an expression or an operator for the actual value of the instance to be considered. The JEP proposes to shatter that boundary, saying that the language should now examine not only the type but also the value of the instance in order to determine flow control. The root cause of the issue here is trying to treat Object hierarchy conversion and conversion between different primitive types as being somehow equivalent. They are not. Java does not have a mechanism that allows a LocalDate to be assigned to a String, even though there is a perfectly reasonable way to do so. Instead, you have to explicitly perform the conversion by calling toString(). That is because `LocalDate` and `String` are separate types with no subtype hierarchy. Similarly, there is no subtype hierarchy link between `int` and `long`. That an `int` can be assigned to a `long` is merely a convenience - it could have required a method call. Critically though, the convenience conversion is absolute. No runtime check of the value of the instance is required. This even applies when converting `int` to `float` which is lossy. In my view, the only pattern matching checks that make sense here are those in line with the separation between types and values of instances. This basic rule implies: * `int` vs `Integer` and vice versa - OK, as only requires examination of the type and reference/null * `int` vs `byte` - not OK, as an expression is required in order to extract the value of the `int` in order to decide flow control In summary, if this was simply about adding a niche feature for checking whether an `int` actually fits in a `byte` I would have no problem. For example, were the pattern match to be based on an expression (ie. a method call) then I would have no problem. The key issue here is the red line being crossed by having a general-purpose language feature examine the value of the instance outside of an expression. thanks Stephen From joe.darcy at oracle.com Thu Jan 26 22:04:20 2023 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Thu, 26 Jan 2023 14:04:20 -0800 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> Message-ID: <207fc279-986c-9153-cf6e-e359754505c7@oracle.com> Switching on floating-point values is perfectly well-defined. Despite common presentation to the contrary, floating-point numbers are not "fuzzy," they are a precisely-defined subset of real numbers, with some notable special cases. As mentioned in the draft JEP, the matching for floating-point values should use representational equivalence, quoting from java.lang.Double: > The two floating-point values represent the same IEEE 754 /datum/. In > particular, for finite > > values, the sign, exponent > , > and significand components of the floating-point values are the same. > Under this relation: > > * |+0.0| and |-0.0| are distinguished from each other. > * every bit pattern encoding a NaN is considered equivalent to each > other > * positive infinity is equivalent to positive infinity; negative > infinity is equivalent to negative infinity. > > Expressions implementing this equivalence relation include: > > * |Double.doubleToLongBits(a) == Double.doubleToLongBits(b)| > * |Double.valueOf(a).equals(Double.valueOf(b))| > * |Double.compare(a, b) == 0| > > Note that representation equivalence is often an appropriate notion of > equivalence to test the behavior of math libraries > . So, under this approach you could have switch(d) { ??? case -0.0 -> ... ??? case +0.0 -> ... ??? case NaN -> ... // Handles all NaNs ? ... } Operationally, this could be desugared to switching over a long by first mapping the double to long via doubleToLongBits (and *not* raw-long-bits). HTH, -Joe On 1/26/2023 5:15 AM, Remi Forax wrote: > > > ------------------------------------------------------------------------ > > *From: *"Angelos Bimpoudis" > *To: *"amber-dev" > *Sent: *Thursday, January 26, 2023 10:48:47 AM > *Subject: *Draft JEP on Primitive types in patterns, instanceof, > and switch > > Hello all, > > I would like to share this draft JEP with you about primitive > types in patterns, instanceof, and switch: > > https://openjdk.org/jeps/8288476 > > "Enhance pattern matching by allowing primitive types to appear > anywhere in patterns. Extend instanceof to support primitive > types, and extend switch to allow primitive constants as case labels." > > Comments very much welcomed! > > Many thanks, > Angelos > > > I still think that the semantics proposed for pattern matching on > primitive types is useless complexity with the perverse side effect of > normalizing the usage of "default" in pattern matching (too many > examples of this JEP are using "default") but we already discussed that. > > Allowing switching on double and float constants is just wrong. > Rust is actually trying to remove that feature > https://github.com/rust-lang/rust/issues/41255 > > I see no point to make the same mistake. > > Otherwise, the rest is fine. > > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Thu Jan 26 22:05:11 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Thu, 26 Jan 2023 22:05:11 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: <039c67d7-a622-29db-570c-54e306585908@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> Message-ID: <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> On 26/01/2023 21:37, Maurizio Cimadamore wrote: > > For instance, even if we only allow updates to local fields, an > instance initializer can now see these updates. for you, this is > something good, for me this is just something else that developers > would have to remember about initialization order. > Also, thinking some more, I realized that one of the things I find more "offputting", is that putting initialization of instance fields before `super` violates the mental barrier I have (and that I'm sure other developers have too) that the letters `t h i s` should never appear before a super() invocation. And I know it's an assignment, and it special, and the VM can deal with it... but... still... language-wise I think if we can latch onto rules that are fairly simple to explain ("no `this` -explicit or implicit - before this point!!!!), it makes things easier. Maurizio From forax at univ-mlv.fr Thu Jan 26 22:25:52 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Thu, 26 Jan 2023 23:25:52 +0100 (CET) Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <207fc279-986c-9153-cf6e-e359754505c7@oracle.com> References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> <207fc279-986c-9153-cf6e-e359754505c7@oracle.com> Message-ID: <317612412.6193866.1674771952958.JavaMail.zimbra@u-pem.fr> Ahhh, so i'm the one to blame, here. For whatever reason, i get the representational equivalence wrong. Thanks for the explanation Joe, i stand corrected. R?mi > From: "joe darcy" > To: "Remi Forax" , "Angelos Bimpoudis" > > Cc: "amber-dev" > Sent: Thursday, January 26, 2023 11:04:20 PM > Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch > Switching on floating-point values is perfectly well-defined. Despite common > presentation to the contrary, floating-point numbers are not "fuzzy," they are > a precisely-defined subset of real numbers, with some notable special cases. > As mentioned in the draft JEP, the matching for floating-point values should use > representational equivalence, quoting from java.lang.Double: >> The two floating-point values represent the same IEEE 754 datum . In particular, >> for [ >> https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/lang/Double.html#isFinite(double) >> | finite ] values, the sign, [ >> https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/lang/Math.html#getExponent(double) >> | exponent ] , and significand components of the floating-point values are the >> same. Under this relation: >> * +0.0 and -0.0 are distinguished from each other. >> * every bit pattern encoding a NaN is considered equivalent to each other >> * positive infinity is equivalent to positive infinity; negative infinity is >> equivalent to negative infinity. >> Expressions implementing this equivalence relation include: >> * Double.doubleToLongBits(a) == Double.doubleToLongBits(b) >> * Double.valueOf(a).equals(Double.valueOf(b)) >> * Double.compare(a, b) == 0 >> Note that representation equivalence is often an appropriate notion of >> equivalence to test the behavior of [ >> https://download.java.net/java/early_access/jdk21/docs/api/java.base/java/lang/StrictMath.html >> | math libraries ] . > So, under this approach you could have > switch(d) { > case -0.0 -> ... > case +0.0 -> ... > case NaN -> ... // Handles all NaNs > ... > } > Operationally, this could be desugared to switching over a long by first mapping > the double to long via doubleToLongBits (and *not* raw-long-bits). > HTH, > -Joe > On 1/26/2023 5:15 AM, Remi Forax wrote: >>> From: "Angelos Bimpoudis" [ mailto:angelos.bimpoudis at oracle.com | >>> ] >>> To: "amber-dev" [ mailto:amber-dev at openjdk.org | ] >>> Sent: Thursday, January 26, 2023 10:48:47 AM >>> Subject: Draft JEP on Primitive types in patterns, instanceof, and switch >>> Hello all, >>> I would like to share this draft JEP with you about primitive types in patterns, >>> instanceof, and switch: >>> [ https://openjdk.org/jeps/8288476 | https://openjdk.org/jeps/8288476 ] >>> "Enhance pattern matching by allowing primitive types to appear anywhere in >>> patterns. Extend instanceof to support primitive types, and extend switch to >>> allow primitive constants as case labels." >>> Comments very much welcomed! >>> Many thanks, >>> Angelos >> I still think that the semantics proposed for pattern matching on primitive >> types is useless complexity with the perverse side effect of normalizing the >> usage of "default" in pattern matching (too many examples of this JEP are using >> "default") but we already discussed that. >> Allowing switching on double and float constants is just wrong. >> Rust is actually trying to remove that feature >> [ https://github.com/rust-lang/rust/issues/41255 | >> https://github.com/rust-lang/rust/issues/41255 ] >> I see no point to make the same mistake. >> Otherwise, the rest is fine. >> R?mi -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Thu Jan 26 22:46:23 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Thu, 26 Jan 2023 16:46:23 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 4:05 PM Maurizio Cimadamore < maurizio.cimadamore at oracle.com> wrote: > On 26/01/2023 21:37, Maurizio Cimadamore wrote: > > For instance, even if we only allow updates to local fields, an > > instance initializer can now see these updates. for you, this is > > something good, for me this is just something else that developers > > would have to remember about initialization order. > > > Also, thinking some more, I realized that one of the things I find more > "offputting", is that putting initialization of instance fields before > `super` violates the mental barrier I have (and that I'm sure other > developers have too) that the letters `t h i s` should never appear > before a super() invocation. And I know it's an assignment, and it > special, and the VM can deal with it... but... still... language-wise I > think if we can latch onto rules that are fairly simple to explain ("no > `this` -explicit or implicit - before this point!!!!), it makes things > easier. > Well I agree with that sentiment... having a simpler mental model is always nicer. Personally as a developer I would gladly trade that simpler mental model for the warm & secure feeling I'll get when I can KNOW that my final fields are taken care of, before anything else can possibly go wrong with them (maybe restrict to only assignments to local final fields?). And the only people likely to venture into the init-before-super territory are the ones who actually need it... and they will need it badly... the rest of the crowd can keep super() first and keep their model nice & simple. It's kindof like ThreadLocals - you'll know when you need one, and when you do you'll be glad they're there because you realize there's no other way; but until then, you have no need to worry or even know about them. Anyway it sounds like - unless John Rose wants to pick up the fight? - the sentiment here is to only include Brian's item #1, i.e., to allow only purely "static context" code prior to what is to remain a single super()/this() call. I think this is being too conservative but that's just my one opinion. Do we have official agreement on this? I'm happy to keep arguing if not :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 26 23:50:18 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 26 Jan 2023 18:50:18 -0500 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <317612412.6193866.1674771952958.JavaMail.zimbra@u-pem.fr> References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> <207fc279-986c-9153-cf6e-e359754505c7@oracle.com> <317612412.6193866.1674771952958.JavaMail.zimbra@u-pem.fr> Message-ID: <90d024fa-eb59-5386-e068-ec9917f4bde3@oracle.com> Floating point is tricky! On 1/26/2023 5:25 PM, forax at univ-mlv.fr wrote: > Ahhh, > so i'm the one to blame, here. > > For whatever reason, i get the representational equivalence wrong. > > Thanks for the explanation Joe, i stand corrected. > > R?mi > > ------------------------------------------------------------------------ > > *From: *"joe darcy" > *To: *"Remi Forax" , "Angelos Bimpoudis" > > *Cc: *"amber-dev" > *Sent: *Thursday, January 26, 2023 11:04:20 PM > *Subject: *Re: Draft JEP on Primitive types in patterns, > instanceof, and switch > > Switching on floating-point values is perfectly well-defined. > Despite common presentation to the contrary, floating-point > numbers are not "fuzzy," they are a precisely-defined subset of > real numbers, with some notable special cases. > > > As mentioned in the draft JEP, the matching for floating-point > values should use representational equivalence, quoting from > java.lang.Double: > > > The two floating-point values represent the same IEEE 754 > /datum/. In particular, for finite > > values, the sign, exponent > , > and significand components of the floating-point values are > the same. Under this relation: > > * |+0.0| and |-0.0| are distinguished from each other. > * every bit pattern encoding a NaN is considered equivalent > to each other > * positive infinity is equivalent to positive infinity; > negative infinity is equivalent to negative infinity. > > Expressions implementing this equivalence relation include: > > * |Double.doubleToLongBits(a) == Double.doubleToLongBits(b)| > * |Double.valueOf(a).equals(Double.valueOf(b))| > * |Double.compare(a, b) == 0| > > Note that representation equivalence is often an appropriate > notion of equivalence to test the behavior of math libraries > . > > > > So, under this approach you could have > > > switch(d) { > > ??? case -0.0 -> ... > ??? case +0.0 -> ... > ??? case NaN -> ... // Handles all NaNs > ? ... > > } > > > Operationally, this could be desugared to switching over a long by > first mapping the double to long via doubleToLongBits (and *not* > raw-long-bits). > > > HTH, > > > -Joe > > > On 1/26/2023 5:15 AM, Remi Forax wrote: > > > > ------------------------------------------------------------------------ > > *From: *"Angelos Bimpoudis" > *To: *"amber-dev" > *Sent: *Thursday, January 26, 2023 10:48:47 AM > *Subject: *Draft JEP on Primitive types in patterns, > instanceof, and switch > > Hello all, > > I would like to share this draft JEP with you about > primitive types in patterns, instanceof, and switch: > > https://openjdk.org/jeps/8288476 > > "Enhance pattern matching by allowing primitive types to > appear anywhere in patterns. Extend instanceof to support > primitive types, and extend switch to allow primitive > constants as case labels." > > Comments very much welcomed! > > Many thanks, > Angelos > > > I still think that the semantics proposed for pattern matching > on primitive types is useless complexity with the perverse > side effect of normalizing the usage of "default" in pattern > matching (too many examples of this JEP are using "default") > but we already discussed that. > > Allowing switching on double and float constants is just wrong. > Rust is actually trying to remove that feature > https://github.com/rust-lang/rust/issues/41255 > > I see no point to make the same mistake. > > Otherwise, the rest is fine. > > R?mi > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Thu Jan 26 23:50:56 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 26 Jan 2023 18:50:56 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> Message-ID: <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> I think that's where we should start; if we are spectacularly successful, we can come back for more. On 1/26/2023 5:46 PM, Archie Cobbs wrote: > On Thu, Jan 26, 2023 at 4:05 PM Maurizio Cimadamore > wrote: > > On 26/01/2023 21:37, Maurizio Cimadamore wrote: > > For instance, even if we only allow updates to local fields, an > > instance initializer can now see these updates. for you, this is > > something good, for me this is just something else that developers > > would have to remember about initialization order. > > > Also, thinking some more, I realized that one of the things I find > more > "offputting", is that putting initialization of instance fields > before > `super` violates the mental barrier I have (and that I'm sure other > developers have too) that the letters `t h i s` should never appear > before a super() invocation. And I know it's an assignment, and it > special, and the VM can deal with it... but... still... > language-wise I > think if we can latch onto rules that are fairly simple to explain > ("no > `this` -explicit or implicit - before this point!!!!), it makes > things > easier. > > > Well I agree with that sentiment... having a simpler mental model is > always nicer. > > Personally as a developer I would gladly trade that simpler mental > model for the warm & secure feeling I'll get when I can KNOW that my > final fields are taken care of, before anything else can possibly go > wrong with them (maybe restrict to only assignments to local final > fields?). And the only people likely to venture into the > init-before-super territory are the ones who actually need it... and > they will need it badly... the rest of the crowd can keep super() > first and keep their model nice & simple. It's kindof like > ThreadLocals - you'll know when you need one, and when you do you'll > be glad they're there because you realize there's no other way; but > until then, you have no need to worry or even know about them. > > Anyway it sounds like - unless John Rose wants to pick up the fight? - > the sentiment here is to only include Brian's item #1, i.e., to allow > only purely "static context" code prior to what is to remain a single > super()/this() call. I think this is being too conservative but that's > just my one opinion. > > Do we have official agreement on this? I'm happy to keep arguing if not :) > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Thu Jan 26 23:52:05 2023 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Thu, 26 Jan 2023 15:52:05 -0800 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <90d024fa-eb59-5386-e068-ec9917f4bde3@oracle.com> References: <1882463428.5806520.1674738916735.JavaMail.zimbra@u-pem.fr> <207fc279-986c-9153-cf6e-e359754505c7@oracle.com> <317612412.6193866.1674771952958.JavaMail.zimbra@u-pem.fr> <90d024fa-eb59-5386-e068-ec9917f4bde3@oracle.com> Message-ID: <2914cbe3-a08e-d930-b89a-774bf10ea4c8@oracle.com> +1.0000000000000001 -Joe On 1/26/2023 3:50 PM, Brian Goetz wrote: > Floating point is tricky! > > On 1/26/2023 5:25 PM, forax at univ-mlv.fr wrote: >> Ahhh, >> so i'm the one to blame, here. >> >> For whatever reason, i get the representational equivalence wrong. >> >> Thanks for the explanation Joe, i stand corrected. >> >> R?mi >> >> ------------------------------------------------------------------------ >> >> *From: *"joe darcy" >> *To: *"Remi Forax" , "Angelos Bimpoudis" >> >> *Cc: *"amber-dev" >> *Sent: *Thursday, January 26, 2023 11:04:20 PM >> *Subject: *Re: Draft JEP on Primitive types in patterns, >> instanceof, and switch >> >> Switching on floating-point values is perfectly well-defined. >> Despite common presentation to the contrary, floating-point >> numbers are not "fuzzy," they are a precisely-defined subset of >> real numbers, with some notable special cases. >> >> >> As mentioned in the draft JEP, the matching for floating-point >> values should use representational equivalence, quoting from >> java.lang.Double: >> >> >> The two floating-point values represent the same IEEE 754 >> /datum/. In particular, for finite >> >> values, the sign, exponent >> , >> and significand components of the floating-point values are >> the same. Under this relation: >> >> * |+0.0| and |-0.0| are distinguished from each other. >> * every bit pattern encoding a NaN is considered equivalent >> to each other >> * positive infinity is equivalent to positive infinity; >> negative infinity is equivalent to negative infinity. >> >> Expressions implementing this equivalence relation include: >> >> * |Double.doubleToLongBits(a) == Double.doubleToLongBits(b)| >> * |Double.valueOf(a).equals(Double.valueOf(b))| >> * |Double.compare(a, b) == 0| >> >> Note that representation equivalence is often an appropriate >> notion of equivalence to test the behavior of math libraries >> . >> >> >> >> So, under this approach you could have >> >> >> switch(d) { >> >> ??? case -0.0 -> ... >> ??? case +0.0 -> ... >> ??? case NaN -> ... // Handles all NaNs >> ? ... >> >> } >> >> >> Operationally, this could be desugared to switching over a long >> by first mapping the double to long via doubleToLongBits (and >> *not* raw-long-bits). >> >> >> HTH, >> >> >> -Joe >> >> >> On 1/26/2023 5:15 AM, Remi Forax wrote: >> >> >> >> ------------------------------------------------------------------------ >> >> *From: *"Angelos Bimpoudis" >> *To: *"amber-dev" >> *Sent: *Thursday, January 26, 2023 10:48:47 AM >> *Subject: *Draft JEP on Primitive types in patterns, >> instanceof, and switch >> >> Hello all, >> >> I would like to share this draft JEP with you about >> primitive types in patterns, instanceof, and switch: >> >> https://openjdk.org/jeps/8288476 >> >> "Enhance pattern matching by allowing primitive types to >> appear anywhere in patterns. Extend instanceof to support >> primitive types, and extend switch to allow primitive >> constants as case labels." >> >> Comments very much welcomed! >> >> Many thanks, >> Angelos >> >> >> I still think that the semantics proposed for pattern >> matching on primitive types is useless complexity with the >> perverse side effect of normalizing the usage of "default" in >> pattern matching (too many examples of this JEP are using >> "default") but we already discussed that. >> >> Allowing switching on double and float constants is just wrong. >> Rust is actually trying to remove that feature >> https://github.com/rust-lang/rust/issues/41255 >> >> I see no point to make the same mistake. >> >> Otherwise, the rest is fine. >> >> R?mi >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Fri Jan 27 02:39:52 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Thu, 26 Jan 2023 21:39:52 -0500 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: <99642744-6650-1918-c750-04a50c9d15e5@oracle.com> On 1/26/2023 5:01 PM, Stephen Colebourne wrote: > "On Thu, 26 Jan 2023 at 09:49, Angelos Bimpoudis > wrote: >> I would like to share this draft JEP with you about primitive types in patterns, instanceof, and switch: >> >> https://openjdk.org/jeps/8288476 >> >> "Enhance pattern matching by allowing primitive types to appear anywhere in patterns. Extend instanceof to support primitive types, and extend switch to allow primitive constants as case labels." >> >> Comments very much welcomed! > I am implacably opposed to this JEP. Yes, you've aired these concerns several times before, both publicly and privately, and I figured you probably were not going to change your mind.? Unfortunately, while I understand where your objections come from, after reading them carefully many times, in the end, I still don't find them persuasive.? If it makes you feel better, your arguments (and those of others) did help us come to a better understanding of what we want to do here, but unfortunately it couldn't change the fact that you have a different idea of how the language should be evolved than we do.? In a community as large as Java, it is inevitable that this occasionally happens. You are looking at this feature bottom-up, as in "would I want to write code to do this", and as a user of the language, that makes sense -- you're trying to figure out what new programs it lets you write, and evaluating how interested you are in writing those programs.? But our motivation for this JEP is top-down; it is about driving the language to a more consistent place, where aggregation and decomposition not are both compositional, but compose in precisely the same way (only in reverse), so we can take apart the composition of aggregations with the composition of similar patterns -- without having to reason about arbitrary distinctions like "unless it involved a primitive widening." I've covered some of the specifics of this goal in greater detail in numerous previous mails, so I don't want to repeat them here. Here's one example: ?- https://mail.openjdk.org/pipermail/amber-dev/2022-November/007601.html > I think it breaks a fundamental > tenet of the Java language I realize you feel unheard because you haven't been able to convince us to your point of view, but escalating to hyperbole ("fundamental tenet", "red line", "shatter") or insulting rhetoric ("utterly nonsensical"), doesn't help your case.? I won't be responding to these parts. > A large part of the Goals and Motivation section are focussed on the > question of how to check and convert from `int` to `byte` or similar. I actually agree with this point -- that the goals and motivation don't tell the whole story.? This is an early draft of the JEP, and the goals and motivations need to be tightened up to capture the bigger picture.? We'll be evolving the goals and motivation as we go.? Comments are welcome on how to improve the JEP draft, but we're past the "is this a good idea" stage. > This isn't a problem people are crying out to be fixed. As has been explained before, not all language changes need to be reactions to "things people already perceive as pain points". You've already several times offered feedback that rounds to "I wish pattern matching were a smaller feature".? But there is a big agenda for pattern matching here, and we're looking ahead to where we're trying to get to, not just the next meter of pavement.? People have not yet started to use sophisticated nested patterns, so they haven't experienced this pain yet -- but they will, if we don't head it off before they get there. > There is simply no comparison here. Dog and Animal are subtypes of > Pet, a concept that has been baked into the language since day one, > and is fully understood by all. By contrast, there is absolutely no > subtyping relationship between int, byte and short, and again this > fact has been baked into the language since day one. You've floated this theory before -- that instanceof "is" a subtype check, "full stop".? And I can't fault you for choosing this particular mental model -- it's a useful one, or at least it has been so far.? But it's quite a leap to claim that somehow this is the only way it would ever be reasonable to think about it, and peppering your claims with more absolutes doesn't make it so. In reality, `instanceof` is closely related to _casting_.? In pre-patterns code, nearly 100% of instanceof checks are followed by a cast to the same type (why else would you ask instanceof?), and almost as many casts are preceded by an instanceof for that same type (and many that don't are bugs).? This is not an accident. Instanceof is how we ask whether it would it be safe to cast to a given type, before doing something that might fail.? It has been restricted to reference types for reasons that were sensible in 1995, started to fray when we added autoboxing, are fraying further now that we have nested patterns, and will further unravel when we get to Valhalla.? But if you read JLS Ch5 enough times and listen carefully, *it already tells you* what `instanceof` means when applied to primitives!? It means the same thing as for references -- "would it be safe to cast to this type".? The set of things that can go wrong when casting to/from primitives are slightly different -- you can lose precision silently instead of throwing CCE loudly -- but it is the same question, and the answer is sitting there in JLS Ch5 already.? (This is covered in greater detail in the linked-to message above.) A telling thing is that if you look at the spec of this work, what you'll see is that it is almost entirely _removing_ existing restrictions; the main thing that is added is a definition of when a cast is "lossy" and when it is "exact" (and these are exactly what you'd expect them to be.)? The rest flows entirely from the existing definition of cast conversion and that `instanceof` is the precondition for casting being safe.? There's almost nothing new here, just exposing what is already there to a broader domain. I get that this seems uncomfortable to some; if you cannot get past the belief that instanceof could only ever be about subtyping between reference types, you're going to tie yourself in knots.? But "instanceof is about subtyping" is merely one convenient way to explain the current behavior.? But its kinship with casting is deeper than that. > The root cause of the issue here is trying to treat Object hierarchy > conversion and conversion between different primitive types as being > somehow equivalent. They are not. Java does not have a mechanism that > allows a LocalDate to be assigned to a String, even though there is a > perfectly reasonable way to do so. Instead, you have to explicitly > perform the conversion by calling toString(). That is because > `LocalDate` and `String` are separate types with no subtype hierarchy. I'm glad you bring up "assignment".? Assignment is covered in JLS 5.2, "Assignment context".? And note that the word "subtyping" does not appear in JLS 5.2!? What it says is that in an assignment context, the conversions that are allowed include widening primitive conversion (int to long), widening reference conversion (String to Object), boxing conversion (int to Integer), and certain others. The language used by the spec here doesn't treat subtyping as something special; it even uses the same word to describe "int to long" as it does for "String to Object" -- they are both widening conversions. Look, I get it.? Individual developers are free to come up with their own mental models for how the language works, and mental models can be immensely useful.? But we shouldn't confuse our mental models with Universal Truth, and sometimes reality takes a turn we didn't expect, and it can be momentarily disorienting. > In my view, the only pattern matching checks that make sense here are > those in line with the separation between types and values of > instances. That is one view, and I'm not going to say it is intrinsically bad. But there are more things in heaven and earth. Our goal is to evolve the language consistently both with where it has come from, and with a view towards where we are going -- and our goals for pattern matching are deeper than merely fusing type tests and casts.? As a result, we may push things farther than you would, and that's OK. But the arguments you make, while passionate, are basically circular; you've assumed a "how it is" that can lead only to "how you want it to be." I realize you won't be convinced, and there may be others in the same boat -- and that's fine.? If you have *new* arguments that can be expressed constructively, they are welcome, but rehashing the same arguments another time is unlikely to be helpful. In ten years, if you still disagree that this wasn't the right move, I'll buy the beers.? But I'm pretty sure I won't have to; I think this will make a lot more sense in the rear-view mirror than it feels right now looking down the road. From amaembo at gmail.com Fri Jan 27 06:22:09 2023 From: amaembo at gmail.com (Tagir Valeev) Date: Fri, 27 Jan 2023 07:22:09 +0100 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: Hello! On Thu, Jan 26, 2023, 23:01 Stephen Colebourne wrote: > > > In the Motivation section it is claimed that because `byte b = 42` > compiles, it implies that sometimes an `int` can be converted to a > `byte` without a cast. This is nonsense. In this context, `42` is > *not* an `int` at all - it is a literal. There is no conversion here, > `42` is typed as a `byte` because of the assignment. `42` is never, at > any stage, an `int`. At the very least, the JEP should be amended to > remove this part of the Motivation section. > A small correction: this is not what spec says. 42 is accepted here not because it's untyped literal but because it's a compile time constant expression that fits the byte type. Other constant expressions are also accepted here, like: byte b = 21 + 21; // obviously not literal Or even: final int x = 21; final int y = 21; // int type is even spelled explicitly byte b = x + y; With best regards, Tagir Valeev > The document proceeds to argue that because switch works with Object > hierarchies: > Pet p = new Pet(new Dog()); // automatic widening conversion from > Dog to Animal > switch (p) { > case Pet(Dog d) -> ... d ... > case Pet(Animal a) -> ... a ... > default -> ... > } > that it must therefore be OK to work with primitives: > int i = methodReturningShort(); > switch (i) { > case byte b -> ... b ...; > case float f -> ... f ...; > default -> -1; > } > > There is simply no comparison here. Dog and Animal are subtypes of > Pet, a concept that has been baked into the language since day one, > and is fully understood by all. By contrast, there is absolutely no > subtyping relationship between int, byte and short, and again this > fact has been baked into the language since day one. > > There is a *huge* red line being crossed here. Values in Java have two > distinct parts - the type and the value of the instance. Java has > always kept these two things completely separate: General-purpose > language features operate on types and references/null (eg. > instanceof, catch, switch) or expressions (if, for, while). It > requires an expression or an operator for the actual value of the > instance to be considered. The JEP proposes to shatter that boundary, > saying that the language should now examine not only the type but also > the value of the instance in order to determine flow control. > > The root cause of the issue here is trying to treat Object hierarchy > conversion and conversion between different primitive types as being > somehow equivalent. They are not. Java does not have a mechanism that > allows a LocalDate to be assigned to a String, even though there is a > perfectly reasonable way to do so. Instead, you have to explicitly > perform the conversion by calling toString(). That is because > `LocalDate` and `String` are separate types with no subtype hierarchy. > Similarly, there is no subtype hierarchy link between `int` and > `long`. That an `int` can be assigned to a `long` is merely a > convenience - it could have required a method call. Critically though, > the convenience conversion is absolute. No runtime check of the value > of the instance is required. This even applies when converting `int` > to `float` which is lossy. > > In my view, the only pattern matching checks that make sense here are > those in line with the separation between types and values of > instances. This basic rule implies: > * `int` vs `Integer` and vice versa - OK, as only requires examination > of the type and reference/null > * `int` vs `byte` - not OK, as an expression is required in order to > extract the value of the `int` in order to decide flow control > > In summary, if this was simply about adding a niche feature for > checking whether an `int` actually fits in a `byte` I would have no > problem. For example, were the pattern match to be based on an > expression (ie. a method call) then I would have no problem. The key > issue here is the red line being crossed by having a general-purpose > language feature examine the value of the instance outside of an > expression. > > thanks > Stephen > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Fri Jan 27 08:59:36 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 27 Jan 2023 08:59:36 +0000 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> > On 26 Jan 2023, at 22:01, Stephen Colebourne wrote: > > In this context, `42` is *not* an `int` at all - it is a literal. There is no conversion here, > `42` is typed as a `byte` because of the assignment. `42` is never, at > any stage, an `int`. See JLS ?3.10.1 and ?5.2. > There is simply no comparison here. Dog and Animal are subtypes of > Pet, a concept that has been baked into the language since day one, > and is fully understood by all. By contrast, there is absolutely no > subtyping relationship between int, byte and short Whether or not there?s any comparison here is debatable, but until, like, five minutes ago switch couldn?t switch on types, and now that switch *must* switch on type relationships is an eternal cornerstone of Java? Also, you may want to look at JLS ?4.10.1. > saying that the language should now examine not only the type but also > the value of the instance in order to determine flow control. I believe switch has examined values to determine control flow for quite some time now. > The root cause of the issue here is trying to treat Object hierarchy > conversion and conversion between different primitive types as being > somehow equivalent. Not equivalent. Rather, the JEP generalises patterns into a concept that encompasses both. It reinterprets what patterns are about: "Despite having been restricted to reference types, instanceof is in principle about asking whether an upcoming cast of a value to a type would succeed without loss of information or error.? Given that patterns, as a new general concept, are all about reinterpreting old concepts and extrapolating from them, pointing out that other extrapolations are possible is not exactly calling out the emperor?s new clothes. ? Ron P.S. The tone of your email was a jot hysterical, which did not aid comprehension and was implacably annoying. Maybe tone it down next time From forax at univ-mlv.fr Fri Jan 27 11:06:30 2023 From: forax at univ-mlv.fr (Remi Forax) Date: Fri, 27 Jan 2023 12:06:30 +0100 (CET) Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> Message-ID: <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> ----- Original Message ----- > From: "Ron Pressler" > To: "Stephen Colebourne" > Cc: "amber-dev" > Sent: Friday, January 27, 2023 9:59:36 AM > Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and switch >> On 26 Jan 2023, at 22:01, Stephen Colebourne wrote: >> >> In this context, `42` is *not* an `int` at all - it is a literal. There is no >> conversion here, >> `42` is typed as a `byte` because of the assignment. `42` is never, at >> any stage, an `int`. > > > See JLS ?3.10.1 and ?5.2. > > >> There is simply no comparison here. Dog and Animal are subtypes of >> Pet, a concept that has been baked into the language since day one, >> and is fully understood by all. By contrast, there is absolutely no >> subtyping relationship between int, byte and short > > > Whether or not there?s any comparison here is debatable, but until, like, > five minutes ago switch couldn?t switch on types, and now that switch *must* > switch on type relationships is an eternal cornerstone of Java? > > Also, you may want to look at JLS ?4.10.1. > > >> saying that the language should now examine not only the type but also >> the value of the instance in order to determine flow control. > > > I believe switch has examined values to determine control flow for quite some > time now. > > >> The root cause of the issue here is trying to treat Object hierarchy >> conversion and conversion between different primitive types as being >> somehow equivalent. > > > Not equivalent. Rather, the JEP generalises patterns into a concept that > encompasses > both. It reinterprets what patterns are about: "Despite having been restricted > to > reference types, instanceof is in principle about asking whether an upcoming > cast of a > value to a type would succeed without loss of information or error.? > > Given that patterns, as a new general concept, are all about reinterpreting old > concepts > and extrapolating from them, pointing out that other extrapolations are possible > is not > exactly calling out the emperor?s new clothes. The problem with extrapoling/re-interpreting is where to stop, where to draw the line. Most languages that have C as ancestor have tried to separate the different casts into different categories, considering using the same syntax for different kind of casts as a mistake. Re-interpreting "instanceof" as a question if any casts will succeed and not just reference casts is a huge leap of faith that feels backward. Generations of Java developers have a pretty good grasp of the difference between subtyping and primitive conversions, this proposal acts as a wrecking ball and shatter that. By example, you can not override a method that returns a double with a method that returns an int because overriding is about subtyping relationship, not conversion (for the history, Neal Gafter had implemented method overriding that allow primitive conversions in javac in one of the early versions of Java 1.5 but to it was decided to not go that path). I agree that revisiting concepts is something we have to do, but breaking the difference between subtyping and primitive conversions for a corner case, in isolation, is a decision hard to understand. > > ? Ron > > P.S. > > The tone of your email was a jot hysterical, which did not aid comprehension and > was implacably annoying. Stephen is like a lot of us, invested in Java. > Maybe tone it down next time R?mi From redio.development at gmail.com Fri Jan 27 11:21:28 2023 From: redio.development at gmail.com (Red IO) Date: Fri, 27 Jan 2023 12:21:28 +0100 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> Message-ID: I don't see why we need a language change here. Why not add safecast methods and is in bounds methods in the primitive wrapper classes. Like: Byte.isInBounds(56L) And byte b = Byte.castOrThrow(56L); Or Optional b = Byte.cast(56L); Of cause the latter one would be quite inefficient in the current (pre Valhalla) world. I don't see many cases where someone might switch on a primitive and have many cases like in the examples (float to int, long, byte..) Great regards RedIODev On Fri, Jan 27, 2023, 12:06 Remi Forax wrote: > ----- Original Message ----- > > From: "Ron Pressler" > > To: "Stephen Colebourne" > > Cc: "amber-dev" > > Sent: Friday, January 27, 2023 9:59:36 AM > > Subject: Re: Draft JEP on Primitive types in patterns, instanceof, and > switch > > >> On 26 Jan 2023, at 22:01, Stephen Colebourne > wrote: > >> > >> In this context, `42` is *not* an `int` at all - it is a literal. > There is no > >> conversion here, > >> `42` is typed as a `byte` because of the assignment. `42` is never, at > >> any stage, an `int`. > > > > > > See JLS ?3.10.1 and ?5.2. > > > > > >> There is simply no comparison here. Dog and Animal are subtypes of > >> Pet, a concept that has been baked into the language since day one, > >> and is fully understood by all. By contrast, there is absolutely no > >> subtyping relationship between int, byte and short > > > > > > Whether or not there?s any comparison here is debatable, but until, like, > > five minutes ago switch couldn?t switch on types, and now that switch > *must* > > switch on type relationships is an eternal cornerstone of Java? > > > > Also, you may want to look at JLS ?4.10.1. > > > > > >> saying that the language should now examine not only the type but also > >> the value of the instance in order to determine flow control. > > > > > > I believe switch has examined values to determine control flow for quite > some > > time now. > > > > > >> The root cause of the issue here is trying to treat Object hierarchy > >> conversion and conversion between different primitive types as being > >> somehow equivalent. > > > > > > Not equivalent. Rather, the JEP generalises patterns into a concept that > > encompasses > > both. It reinterprets what patterns are about: "Despite having been > restricted > > to > > reference types, instanceof is in principle about asking whether an > upcoming > > cast of a > > value to a type would succeed without loss of information or error.? > > > > Given that patterns, as a new general concept, are all about > reinterpreting old > > concepts > > and extrapolating from them, pointing out that other extrapolations are > possible > > is not > > exactly calling out the emperor?s new clothes. > > The problem with extrapoling/re-interpreting is where to stop, where to > draw the line. > Most languages that have C as ancestor have tried to separate the > different casts into different categories, considering using the same > syntax for different kind of casts as a mistake. > Re-interpreting "instanceof" as a question if any casts will succeed and > not just reference casts is a huge leap of faith that feels backward. > > Generations of Java developers have a pretty good grasp of the difference > between subtyping and primitive conversions, this proposal acts as a > wrecking ball and shatter that. > By example, you can not override a method that returns a double with a > method that returns an int because overriding is about subtyping > relationship, not conversion (for the history, Neal Gafter had implemented > method overriding that allow primitive conversions in javac in one of the > early versions of Java 1.5 but to it was decided to not go that path). > > I agree that revisiting concepts is something we have to do, but breaking > the difference between subtyping and primitive conversions for a corner > case, in isolation, is a decision hard to understand. > > > > > ? Ron > > > > P.S. > > > > The tone of your email was a jot hysterical, which did not aid > comprehension and > > was implacably annoying. > > Stephen is like a lot of us, invested in Java. > > > Maybe tone it down next time > > R?mi > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Fri Jan 27 12:01:41 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 27 Jan 2023 12:01:41 +0000 Subject: [External] : Re: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> Message-ID: <544D72C6-5037-4B0B-B2D1-B0C6EF0ECA8D@oracle.com> > On 27 Jan 2023, at 11:06, Remi Forax wrote: > > The problem with extrapoling/re-interpreting is where to stop, where to draw the line. > Most languages that have C as ancestor have tried to separate the different casts into different categories, considering using the same syntax for different kind of casts as a mistake. > Re-interpreting "instanceof" as a question if any casts will succeed and not just reference casts is a huge leap of faith that feels backward. There are obviously multiple ways to extrapolate and generalise things ?correctly.? Whatever the generalisation is, opinions on how it feels may vary. The more interesting question is, I think, does the proposes approach lead to actual problems, not whether or not it?s the only possible one. > > Generations of Java developers have a pretty good grasp of the difference between subtyping and primitive conversions, this proposal acts as a wrecking ball and shatter that. ?4.10.1 of the JLS has stated that a subtyping relationship among primitives exists (byte <: short <: int <: long, float <: double) since at least Java 1.6 (possibly earlier). > By example, you can not override a method that returns a double with a method that returns an int because overriding is about subtyping relationship, not conversion (for the history, Neal Gafter had implemented method overriding that allow primitive conversions in javac in one of the early versions of Java 1.5 but to it was decided to not go that path). The rules for return types in overridden methods (?8.4.8.3) doesn?t refer to subtyping but to "return-type-substitutability? (?8.4.5) which, in turn, also doesn?t talk about subtyping but only about subtyping *in the case that the return type is a reference type*. So even though there is a subtyping relationship between int and long (though not between int and double), they are not return-type-substitutable, which places additional constraints beyond mere subtyping. > > I agree that revisiting concepts is something we have to do, but breaking the difference between subtyping and primitive conversions for a corner case, in isolation, is a decision hard to understand. First, a subtyping relationship for primitives does exist, though it doesn?t cover all of the possible conversions. Second, nothing is broken, shattered, or wrecked even in cases subtyping doesn?t exist, because the draft doesn?t propose to *change* the meaning of patterns, but rather to generalise them. I.e. its insight is that subtyping is a special case of assignment conversion, and so patterns are ?really? about the validity of such conversions rather than about the specific case of subtyping. Another way of looking at it is that switch has always been about switching on specific values. Patterns generalise the switch cases to cover a set of values rather than individual ones, where the set of the values covered by the case is the set of all instances of a type. This proposal generalises patterns to further allow other kinds of sets (and, at least in some of those situations, still uses the subtyping relationship even on primitives). I think it?s clear that nothing here is ?broken? or even changed; just generalised in a particular way. We can argue over whether this particular generalisation feels philosophically satisfying (although I think much of it has to do with personal aesthetics), but there is no definitively right or wrong answer, because things can be generalised and extrapolated in many sound ways. It would be helpful, therefore, to explain whether an objection stems from ?aesthetic unease? due to philosophical opinions about the generalisation or a concrete problem that may arise. ? Ron From ron.pressler at oracle.com Fri Jan 27 12:29:30 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 27 Jan 2023 12:29:30 +0000 Subject: [External] : Re: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> Message-ID: <0C5E7802-0CD7-4587-97E5-EDB2DE6DF56D@oracle.com> Because, at least the way I read it ? and perhaps the motivation needs to be clarified ? the point is not so much how to just solve the problem of primitive ranges, but how to best understand patterns. Patterns are a language feature; widening and narrowing conversions for both references and primitives ? with or without explicit casts ? are also a language feature. The interesting insight in the proposal is about how the patterns language feature interacts with the narrowing conversion language feature. It points out that patterns makes narrowing reference conversion (JLS ?5.1.6), aka ?downcasts?, safe for reference types, and so it?s a reasonable generalisation to have patterns also make narrowing primitive conversions (JLS ?5.1.3) safe as well. If patterns are a ?narrowing conversion safeifier? language feature, they should work with all of the language?s narrowing conversions. ? Ron > On 27 Jan 2023, at 11:21, Red IO wrote: > > I don't see why we need a language change here. Why not add safecast methods and is in bounds methods in the primitive wrapper classes. Like: > Byte.isInBounds(56L) > And > byte b = Byte.castOrThrow(56L); > Or > Optional b = Byte.cast(56L); > Of cause the latter one would be quite inefficient in the current (pre Valhalla) world. > > I don't see many cases where someone might switch on a primitive and have many cases like in the examples (float to int, long, byte..) > > Great regards > RedIODev From redio.development at gmail.com Fri Jan 27 13:42:36 2023 From: redio.development at gmail.com (Red IO) Date: Fri, 27 Jan 2023 14:42:36 +0100 Subject: [External] : Re: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <0C5E7802-0CD7-4587-97E5-EDB2DE6DF56D@oracle.com> References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> <0C5E7802-0CD7-4587-97E5-EDB2DE6DF56D@oracle.com> Message-ID: But reference type casts are fundamentally different from primitive number type casts. When we cast rather with instanceof or just an plain old cast we don't alter memory at all. We simply get a reference to the previous memory location with a more specific type. Primitives are copied when casted (at least as far as I know). Sure the cost of copying a primitive is equal or smaller than creating a reference but the concept is a different one. byte is not a subtype of int. It's more like (not valid syntax): int i = new int(5); byte b = new byte(i); They are not related in their types besides the (valid) simple conversions the compiler can do. It's like we would allow: StringBuilder b = (StringBuilder) "original"; Because there is an available conversion between them. Actually some languages like C# do that. But I don't think Java should go that route. Great regards RedIODev On Fri, Jan 27, 2023, 13:29 Ron Pressler wrote: > Because, at least the way I read it ? and perhaps the motivation needs to > be clarified ? the point is not so much how to just solve the problem of > primitive ranges, but how to best understand patterns. Patterns are a > language feature; widening and narrowing conversions for both references > and primitives ? with or without explicit casts ? are also a language > feature. > > The interesting insight in the proposal is about how the patterns language > feature interacts with the narrowing conversion language feature. It points > out that patterns makes narrowing reference conversion (JLS ?5.1.6), aka > ?downcasts?, safe for reference types, and so it?s a reasonable > generalisation to have patterns also make narrowing primitive conversions > (JLS ?5.1.3) safe as well. If patterns are a ?narrowing conversion > safeifier? language feature, they should work with all of the language?s > narrowing conversions. > > ? Ron > > > On 27 Jan 2023, at 11:21, Red IO wrote: > > > > I don't see why we need a language change here. Why not add safecast > methods and is in bounds methods in the primitive wrapper classes. Like: > > Byte.isInBounds(56L) > > And > > byte b = Byte.castOrThrow(56L); > > Or > > Optional b = Byte.cast(56L); > > Of cause the latter one would be quite inefficient in the current (pre > Valhalla) world. > > > > I don't see many cases where someone might switch on a primitive and > have many cases like in the examples (float to int, long, byte..) > > > > Great regards > > RedIODev > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Fri Jan 27 14:06:37 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Fri, 27 Jan 2023 14:06:37 +0000 Subject: [External] : Re: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <89CC19B2-477C-4D9D-B0D8-DACA8865F44F@oracle.com> <638058955.6515654.1674817590871.JavaMail.zimbra@u-pem.fr> <0C5E7802-0CD7-4587-97E5-EDB2DE6DF56D@oracle.com> Message-ID: <9C92B0CD-8665-4E30-88C8-9A46AA212BA5@oracle.com> > On 27 Jan 2023, at 13:42, Red IO wrote: > > But reference type casts are fundamentally different from primitive number type casts. > When we cast rather with instanceof or just an plain old cast we don't alter memory at all. We simply get a reference to the previous memory location with a more specific type. Primitives are copied when casted (at least as far as I know). Sure the cost of copying a primitive is equal or smaller than creating a reference but the concept is a different one. It is a different concept, but the JLS treats them both as sub-concept of a single, wider one called a ?narrowing conversion?, which may either succeed or fail at runtime (and there are different ways to interpret what ?success" means). A pattern match between a value and a pattern is allowed when a narrowing conversion is allowed, and if it succeeds then the narrowing conversion from the value to the pattern is guaranteed to succeed (in the case of primitives, ?success? here is interpreted to mean that the conversion is not lossy). Your point about references and memory copying is also becoming outdated as classes may not represent only types whose values are always accessed by reference (Project Valhalla). So even ?plain? assignments, with or without casts on user-defined classes may involve memory copies. Conversely, primitives are not necessarily copied when cast. For example, if we have `void foo(int x)`, calling `foo((int)myLong)` will not involve an additional copy (if at all, depending on how things are inlined, but now we?re at the VM implementation level, not the language specification level). So the move here is not to conflate subtypes and primitive conversions, but rather to state that patterns operate at the higher, more general level of ?narrowing conversions?, which subsumes both kinds as special cases. It says, don?t think of patterns as a subtype check, but as a narrowing conversion check (which also includes subtypes; see JLS ?5.1.6) ? Ron From brian.goetz at oracle.com Fri Jan 27 14:53:43 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 27 Jan 2023 09:53:43 -0500 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: Message-ID: > In this context, `42` is > *not* an `int` at all - it is a literal. There is no conversion here, I don't really want to pile on because Ron and Tagir have already made it clear that this is simply a misunderstanding of how the language works, but there's a deeper point here that makes it useful to dig in a little bit further, so I ask some forbearance.? First, some necessary chapter and verse: JLS 3.10 defines literals; integer literals are divided into decimal, hex, octal, and binary integer literals.? The spec is quite clear that literals like 42 *are*, in fact, integers: > An integer literal is of type long if it is suffixed with an ASCII > letter L or l (ell); > otherwise it is of type int (?4.2.1). There are no "untyped literals", nor are there literals of type byte, short, or char.? (Fun fact: there are also no instructions in the JVM for arithmetic on byte, short, or char; these are done with `iadd` and friends, and the shorter types are _erased_ to int. Erasure is not just for generics.) JLS 5 (which is about conversions) then goes on to define primitive widening and narrowing conversions, and state when these conversions can be applied.? In an assignment context (JLS 5.2), a special case for narrowing constant integral expressions (which includes integer literals) to shorter integral types is permitted: > In addition, if the expression is a constant expression (?15.29) of > type byte, short, > char, or int: > ? A narrowing primitive conversion may be used if the variable is of > type byte, > short, or char, and the value of the constant expression is > representable in the > type of the variable. This is why `byte b = 0` works; the RHS is a constant expression of type `int`, and 0 is known by the compiler to be representable in the type `byte`.? (This same language -- a value being representable in a given type -- is also the language used in this JEP for when a cast is exact.) So yes, there is a conversion here (JLS 5 is called "conversions and contexts").? There is similar language that permits, for example, integer case labels to be used in a switch on byte, short, or char (or their box types.) Now, let's think about what Java would be like without this phrase in JLS 5.2; we'd have to cast 0 to byte every time we use a literal (or the language would have to have separate syntax for byte literals).? That's kind of annoying; this is the spec working for you so you don't have to deal with, or even notice, these low-level annoyances. My point is not to say "see, haha, Stephen doesn't understand Java" -- quite the opposite.? Stephen is an accomplished Java programmer, who has written excellent Java libraries that we all use every day. My point is that you can be an excellent Java programmer *without fully understanding how the language works* -- and that's a feature, not a bug!? The essence of Java's "blue collar" success is not that the language is so simple that everyone can read and understand the spec in an afternoon.? Java is in fact quite complex, but the spec is so carefully constructed that most developers can go an entire career without opening the spec at all, and much of the complexity stays in the shadows.? The spec goes to great lengths so that programmers like Stephen can enjoy mental models like "42 is not an int, its a literal", and have that not work against them most of the time.? It doesn't matter whether these mental models are 100% accurate; they are still useful. Where mental models become problematic is when they leave your own mind and you try to treat them as some sort of law of physics (especially when they're wrong.)? Mental models are useful, helpful approximations.? "Instanceof means subtyping" is a mental model, just like "0 is not an integer, its a literal."? If they help you, great, but be very careful about extrapolating past the boundary of your own skull. The changes in this JEP are in the same spirit as the rules about narrowing integer constants; it is about _removing_ anomalies that would make construction and deconstruction asymmetric for gratuitous reasons, just like the rule about narrowing integer constants to byte.? We don't notice it because its working quietly for us.? No one clamored for it -- because they never needed to.? If we didn't align the meaning of type patterns with existing conversions, as people used more complex nested patterns, they'd notice anomalies that are analogous to "can't assign 0 to byte". I get that this seems like a big change, but really, it's not.? I doubt people will all of a sudden start using switches on floats all over the place, but it would be weird to be able to switch on every type *but* float.? The cure for that is to ensure that switching, instanceof, and pattern matching work on every type, whose semantics are drawn from a single, common source.? As it turns out, that source is in plain view -- casting.? We just have to let it out. On 1/27/2023 1:22 AM, Tagir Valeev wrote: > Hello! > > On Thu, Jan 26, 2023, 23:01 Stephen Colebourne > wrote: > > > > In the Motivation section it is claimed that because `byte b = 42` > compiles, it implies that sometimes an `int` can be converted to a > `byte` without a cast. This is nonsense. In this context, `42` is > *not* an `int` at all - it is a literal. There is no conversion here, > `42` is typed as a `byte` because of the assignment. `42` is never, at > any stage, an `int`. At the very least, the JEP should be amended to > remove this part of the Motivation section. > > > A small correction: this is not what spec says. 42 is accepted here > not because it's untyped literal but because it's a compile time > constant expression that fits the byte type. Other constant > expressions are also accepted here, like: > > byte b = 21 + 21; // obviously not literal > Or even: > final int x = 21; > final int y = 21; // int type is even spelled explicitly > byte b = x + y; > > With best regards, > Tagir Valeev > > > The document proceeds to argue that because switch works with Object > hierarchies: > ? Pet p = new Pet(new Dog()); // automatic widening conversion from > Dog to Animal > ? switch (p) { > ? ? case Pet(Dog d)? ? -> ... d ... > ? ? case Pet(Animal a) -> ... a ... > ? ? default? ? ? ? ? ? -> ... > ? } > that it must therefore be OK to work with primitives: > ? int i = methodReturningShort(); > ? switch (i) { > ? ? case byte? b -> ... b ...; > ? ? case float f -> ... f ...; > ? ? default? ? ? -> -1; > ? } > > There is simply no comparison here. Dog and Animal are subtypes of > Pet, a concept that has been baked into the language since day one, > and is fully understood by all. By contrast, there is absolutely no > subtyping relationship between int, byte and short, and again this > fact has been baked into the language since day one. > > There is a *huge* red line being crossed here. Values in Java have two > distinct parts - the type and the value of the instance. Java has > always kept these two things completely separate: General-purpose > language features operate on types and references/null (eg. > instanceof, catch, switch) or expressions (if, for, while). It > requires an expression or an operator for the actual value of the > instance to be considered. The JEP proposes to shatter that boundary, > saying that the language should now examine not only the type but also > the value of the instance in order to determine flow control. > > The root cause of the issue here is trying to treat Object hierarchy > conversion and conversion between different primitive types as being > somehow equivalent. They are not. Java does not have a mechanism that > allows a LocalDate to be assigned to a String, even though there is a > perfectly reasonable way to do so. Instead, you have to explicitly > perform the conversion by calling toString(). That is because > `LocalDate` and `String` are separate types with no subtype hierarchy. > Similarly, there is no subtype hierarchy link between `int` and > `long`. That an `int` can be assigned to a `long` is merely a > convenience - it could have required a method call. Critically though, > the convenience conversion is absolute. No runtime check of the value > of the instance is required. This even applies when converting `int` > to `float` which is lossy. > > In my view, the only pattern matching checks that make sense here are > those in line with the separation between types and values of > instances. This basic rule implies: > * `int` vs `Integer` and vice versa - OK, as only requires examination > of the type and reference/null > * `int` vs `byte` - not OK, as an expression is required in order to > extract the value of the `int` in order to decide flow control > > In summary, if this was simply about adding a niche feature for > checking whether an `int` actually fits in a `byte` I would have no > problem. For example, were the pattern match to be based on an > expression (ie. a method call) then I would have no problem. The key > issue here is the red line being crossed by having a general-purpose > language feature examine the value of the instance outside of an > expression. > > thanks > Stephen > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Fri Jan 27 18:16:52 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Fri, 27 Jan 2023 12:16:52 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: On Thu, Jan 26, 2023 at 5:51 PM Brian Goetz wrote: > I think that's where we should start; if we are spectacularly successful, > we can come back for more. > OK thanks. Proceeding... -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From kevinb at google.com Fri Jan 27 19:06:36 2023 From: kevinb at google.com (Kevin Bourrillion) Date: Fri, 27 Jan 2023 11:06:36 -0800 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: <99642744-6650-1918-c750-04a50c9d15e5@oracle.com> References: <99642744-6650-1918-c750-04a50c9d15e5@oracle.com> Message-ID: Not that I've been able to digest this *entire* discussion, but in some ways this is the crux of it for me: On Thu, Jan 26, 2023 at 6:40 PM Brian Goetz wrote: > > In reality, `instanceof` is closely related to _casting_. In > pre-patterns code, nearly 100% of instanceof checks are followed by a > cast to the same type (why else would you ask instanceof?), and almost > as many casts are preceded by an instanceof for that same type (and many > that don't are bugs). This is not an accident. Instanceof is how we ask > whether it would it be safe to cast to a given type, before doing > something that might fail. (First, this claim is something I could gather some data on if it was truly needed, but I don't think it is and I'd put very long odds on it being wrong.) I think the mental models we gravitate to, and that serve us best, are the functional ones: the ones that most tangibly correlate choices we might make to outcomes we might get. Talking of gravity, if I'm standing at the edge of a rooftop, my mental model of gravity is not particles attracting each other by the inverse square, it's "if I take a step, I will at best be in a lot of pain". I think this is one of those cases. *Any* deeper notion of what `instanceof` "really IS" just aren't going to be relevant to programmers. I wanted to add my few lines of support here. But I think, Stephen, that the discussion sparked from your post can probably do no more good here, as you essentially stated up front in your first four words. -- Kevin Bourrillion | Java Librarian | Google, Inc. | kevinb at google.com -------------- next part -------------- An HTML attachment was scrubbed... URL: From pedro.lamarao at prodist.com.br Fri Jan 27 19:21:11 2023 From: pedro.lamarao at prodist.com.br (=?UTF-8?Q?Pedro_Lamar=C3=A3o?=) Date: Fri, 27 Jan 2023 16:21:11 -0300 Subject: Draft JEP on Primitive types in patterns, instanceof, and switch In-Reply-To: References: <99642744-6650-1918-c750-04a50c9d15e5@oracle.com> Message-ID: Em sex., 27 de jan. de 2023 ?s 16:07, Kevin Bourrillion escreveu: > I think the mental models we gravitate to, and that serve us best, are the > functional ones: the ones that most tangibly correlate choices we might > make to outcomes we might get. Talking of gravity, if I'm standing at the > edge of a rooftop, my mental model of gravity is not particles > attracting each other by the inverse square, it's "if I take a step, I will > at best be in a lot of pain". > When your mental model tells you that "chairs are for sitting", and then you need someplace to put your backpack on, then you look at a chair and think, "no this is for sitting not for putting backpacks", then your apparently functional mental model becomes a limiting one. I honestly don't understand what the fuss is about. A new universal dispatch control structure is being designed right in front of our eyes. This discussion is reminding me of Donald Knuth criticizing structured programming. -- Pedro Lamar?o -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Fri Jan 27 20:52:02 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Fri, 27 Jan 2023 14:52:02 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: On Fri, Jan 27, 2023 at 12:16 PM Archie Cobbs wrote: > On Thu, Jan 26, 2023 at 5:51 PM Brian Goetz > wrote: > >> I think that's where we should start; if we are spectacularly successful, >> we can come back for more. >> > > OK thanks. Proceeding... > JEP is updated . Not surprisingly, it has gotten a good bit simpler. Change log... - Removed discussions of 'this' escape, try { } blocks and initialization order - Removed if/then example choosing between two different superclass constructors - Restate JLS changes The updated JLS changes are: 1. Change the grammar for `ConstructorBody` to: ConstructorBody: { [BlockStatements] } ; { [BlockStatements] ExplicitConstructorInvocation [BlockStatements] } ; 2. Specify that the BlockStatements prior to ExplicitConstructorInvocation are in a static context (?8.1.3) Reload & resume firing... :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Fri Jan 27 21:32:15 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Fri, 27 Jan 2023 16:32:15 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: <436312fb-52e8-abe6-b9a1-0267225fd8f4@oracle.com> This is coming together nicely! Good catch on "can't have a return"; the precise way to state this is "statements that can complete abruptly for reasons X, Y and Z" (see JLS 14.1). The static context applies not only to the BlockStatements prior, but also the ExplicitCtorInvocation. On 1/27/2023 3:52 PM, Archie Cobbs wrote: > On Fri, Jan 27, 2023 at 12:16 PM Archie Cobbs > wrote: > > On Thu, Jan 26, 2023 at 5:51 PM Brian Goetz > wrote: > > I think that's where we should start; if we are spectacularly > successful, we can come back for more. > > > OK thanks. Proceeding... > > > JEP is updated . Not > surprisingly, it has gotten a good bit simpler. > > Change log... > > - Removed discussions of 'this' escape, try { } blocks and > initialization order > - Removed if/then example choosing between two different superclass > constructors > - Restate JLS changes > > The updated JLS changes are: > > 1. Change the grammar for `ConstructorBody` to: > > ? ? ConstructorBody: > ? ? ? ? { [BlockStatements] } ; > ? ? ? ? { [BlockStatements] ExplicitConstructorInvocation > [BlockStatements] } ; > > 2. Specify that the BlockStatements prior to > ExplicitConstructorInvocation are in a static context (?8.1.3) > > Reload & resume firing... :) > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Fri Jan 27 21:54:40 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 27 Jan 2023 21:54:40 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: I see that you have basically left the discussion on remapping exception (even though there?s no section on it). IMHO that is still confusing. The first example ends up like this: |public PositiveBigInteger(long value) { super(value); // potentially doing useless work here if (value <= 0) throw new IllegalArgumentException("non-positive value"); } | The second example ends up like this: |public class CustomDeflaterInputStream extends DeflaterInputStream { public CustomDeflaterInputStream(InputStream in) { if (in == null) throw new IllegalArgumentException("null input"); super(in); // we avoided NullPointerException thrown here } } | Both are in the form ?if (something) throw?. To me that is just parameter vaildation. The exact reason as to why parameter validation might be helpful in each case is irrelevant here - the two examples are morally equivalent - or, at the very least, the second example doesn?t deserve ?all that space? in the JEP. You have three very very nice examples: * parameter validation * passing argument twice * complex initialization I?d say just add three sections with one example each and call it a day. Unless you can thing of something that looks more ?qualitatively? different. Maurizio On 27/01/2023 20:52, Archie Cobbs wrote: > On Fri, Jan 27, 2023 at 12:16 PM Archie Cobbs > wrote: > > On Thu, Jan 26, 2023 at 5:51 PM Brian Goetz > wrote: > > I think that's where we should start; if we are spectacularly > successful, we can come back for more. > > > OK thanks. Proceeding... > > > JEP is updated . Not > surprisingly, it has gotten a good bit simpler. > > Change log... > > - Removed discussions of 'this' escape, try { } blocks and > initialization order > - Removed if/then example choosing between two different superclass > constructors > - Restate JLS changes > > The updated JLS changes are: > > 1. Change the grammar for `ConstructorBody` to: > > ? ? ConstructorBody: > ? ? ? ? { [BlockStatements] } ; > ? ? ? ? { [BlockStatements] ExplicitConstructorInvocation > [BlockStatements] } ; > > 2. Specify that the BlockStatements prior to > ExplicitConstructorInvocation are in a static context (?8.1.3) > > Reload & resume firing... :) > > -Archie > > -- > Archie L. Cobbs ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Fri Jan 27 21:55:43 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Fri, 27 Jan 2023 21:55:43 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: <537c3a77-d7f2-6f56-a6f9-813a9f3bc0a1@oracle.com> (resending with right formatting, sorry) I see that you have basically left the discussion on remapping exception (even though there?s no section on it). IMHO that is still confusing. The first example ends up like this: |public PositiveBigInteger(long value) { super(value); // potentially doing useless work here if (value <= 0) throw new IllegalArgumentException("non-positive value"); } | | The second example ends up like this: |public class CustomDeflaterInputStream extends DeflaterInputStream { public CustomDeflaterInputStream(InputStream in) { if (in == null) throw new IllegalArgumentException("null input"); super(in); // we avoided NullPointerException thrown here } } | Both are in the form ?if (something) throw?. To me that is just parameter vaildation. The exact reason as to why parameter validation might be helpful in each case is irrelevant here - the two examples are morally equivalent - or, at the very least, the second example doesn?t deserve ?all that space? in the JEP. You have three very very nice examples: * parameter validation * passing argument twice * complex initialization I?d say just add three sections with one example each and call it a day. Unless you can thing of something that looks more ?qualitatively? different. Maurizio On 27/01/2023 20:52, Archie Cobbs wrote: On Fri, Jan 27, 2023 at 12:16 PM Archie Cobbs > wrote: On Thu, Jan 26, 2023 at 5:51 PM Brian Goetz > wrote: I think that?s where we should start; if we are spectacularly successful, we can come back for more. OK thanks. Proceeding? JEP is updated https://bugs.openjdk.org/browse/JDK-8300786. Not surprisingly, it has gotten a good bit simpler. Change log? * Removed discussions of ?this? escape, try { } blocks and initialization order - Removed if/then example choosing between two different superclass constructors - Restate JLS changes The updated JLS changes are: 1. Change the grammar for |ConstructorBody| to: ConstructorBody: { [BlockStatements] } ; { [BlockStatements] ExplicitConstructorInvocation [BlockStatements] } ; 1. Specify that the BlockStatements prior to ExplicitConstructorInvocation are in a static context (?8.1.3) Reload & resume firing? :) -Archie ? Archie L. Cobbs ? -------------- next part -------------- An HTML attachment was scrubbed... URL: From john.r.rose at oracle.com Sat Jan 28 02:19:45 2023 From: john.r.rose at oracle.com (John Rose) Date: Fri, 27 Jan 2023 18:19:45 -0800 Subject: Loosening requirements for super() invocation In-Reply-To: References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> Message-ID: <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> On 26 Jan 2023, at 11:19, Maurizio Cimadamore wrote: > On 26/01/2023 18:16, Archie Cobbs wrote: >> Yes, but for this to happen the subclass would have to be in effect >> intentionally subverting the superclass constructor. >> >> In other words, a problem like you describe can't suddenly just start >> happening "by accident" just because this new feature exists... > > Well, you could have a subclass (in some client jar) which "subverts" > as you say, some superclass in a library. Perhaps the library was not > prepared for that kind of behavior, and now there's a new bug. > > IMHO, we should try to stay well clear of that can of worms. It's not > like we have to open it now either - the other things you propose are > 100% non-controversial. Just to be clear: Early assignment to a *super* field is never possible, nor is any access other than *writing* a *local* field. No instance method calls to the uninitialized ?this?, and no instance field reads of any kind from it, and no instance field writes to fields defined non-locally. Before the super-constructor call, the object cannot assume that super-class invariants have been set up, so no API point of the super-class can be touched, except to call a constructor. So the JVM doesn?t permit non-local early accesses (early meaning ?before super constructor call?) because that would allow subclasses to inject actions into superclass state before the superclass initialization sequence. And that could, indeed, subvert invariants intended by the superclass author. But if a superclass sticks its nose into the business of a subclass, by down-casting, or by calling an overridden virtual from its constructor, then we must hope that the subclass has set things up so that the superclass sees something consistent. Archie?s proposals generally give subclass authors more freedom to set things up nicely before the super-constructor is called. That doesn?t lead to any increased subversion, only better control by the subclass of its proper concerns, by which I mean local concerns, in the same source file. I must be missing your point here Maurizio? There is some corner case you are concerned with but I can?t see where the danger is. ? John -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Sat Jan 28 15:50:42 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Sat, 28 Jan 2023 09:50:42 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <436312fb-52e8-abe6-b9a1-0267225fd8f4@oracle.com> References: <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> <436312fb-52e8-abe6-b9a1-0267225fd8f4@oracle.com> Message-ID: Brian Goetz wrote: > Good catch on "can't have a return"; the precise way to state this is > "statements that can complete abruptly for reasons X, Y and Z" (see JLS > 14.1). > > The static context applies not only to the BlockStatements prior, but also > the ExplicitCtorInvocation. > Thanks! These fixes are included now. Maurizio Cimadamore wrote: > I?d say just add three sections with one example each and call it a day. > Sounds reasonable - done. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Sat Jan 28 16:03:26 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Sat, 28 Jan 2023 10:03:26 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> References: <5B251F9E-09FF-4D7B-BD7B-5A0AEA59C636@oracle.com> <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> Message-ID: On Fri, Jan 27, 2023 at 8:19 PM John Rose wrote: > On 26 Jan 2023, at 11:19, Maurizio Cimadamore wrote: > > On 26/01/2023 18:16, Archie Cobbs wrote: > > Yes, but for this to happen the subclass would have to be in effect > intentionally subverting the superclass constructor. > > In other words, a problem like you describe can't suddenly just start > happening "by accident" just because this new feature exists... > > Well, you could have a subclass (in some client jar) which "subverts" as > you say, some superclass in a library. Perhaps the library was not prepared > for that kind of behavior, and now there's a new bug. > > IMHO, we should try to stay well clear of that can of worms. It's not like > we have to open it now either - the other things you propose are 100% > non-controversial. > > Just to be clear: > > Early assignment to a *super* field is never possible > Ah, you are correct. I was missing this nuance and incorrectly thinking it was allowed to write to *any* field in the object prior to super(). JVMS ?4.10.2.4: > Before that method invokes another instance initialization method of > myClass or its direct superclass on this, the only operation the method > can perform on this is assigning fields *declared within myClass*. > So that whole discussion about writing to superclass fields prior to super() is moot. I must be missing your point here Maurizio? There is > some corner case you are concerned with but I can?t see > where the danger is. > Yes... and now me too :) -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From maurizio.cimadamore at oracle.com Sat Jan 28 21:49:01 2023 From: maurizio.cimadamore at oracle.com (Maurizio Cimadamore) Date: Sat, 28 Jan 2023 21:49:01 +0000 Subject: Loosening requirements for super() invocation In-Reply-To: <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> Message-ID: <6ad45d5b-6a8e-4859-1c6b-02cfb486d53b@oracle.com> On 28/01/2023 02:19, John Rose wrote: > I must be missing your point here Maurizio? There is > some corner case you are concerned with but I can?t see > where the danger is. My point was not about "danger" but about "complex programming model", and "return on complexity". Allowing initialization of local fields before super() call would at the very least cause observable behavior changes in all the instance initializers of the class (there was such an example in the previous version of the JEP I believe). So my point was: why do we need to go there? That is not (anymore) about allowing programs which were rejected for obtuse reasons. This starts going down a path of messing with initialization order (e.g. moving a field initializer, even if local, across the "super" call is _not_ a compatible change). It maybe failure of imagination - but aside from pathological cases (like classes whose initialization lets `this` escape - which I think we all agree are on the bad side of the spectrum) I can't think of why you would want to do that. The fact that the JVM allows it, and that it does so in a sound fashion (which is what I'd expect the JVM to do) is irrelevant in my consideration. To put it more clearly - it is quite clear as to why one might want to: * do validation on constructor parameter before a super call * pass constructor parameter twice * do some complex initialization which requires control flow These are things that add a net improvement on language expressiveness, and do that with a very simple rule: you cannot spell `this` before the super() call, which is easy to remember, and close to what users would expect. To add the next bit, the model is: you cannot spell `this` except if it's an initializer of a field. But wait, not any field, it has to be a "local" field (this names is, btw, not great, as in Java I only know about "local variables") - so that concept also comes with the ride. Of course these concepts aren't hard to teach, but I think before we go there we should have better arguments of _why_ we need to, as the examples I've seen so far seem a bit on the thin side. And, doing the points above doesn't prevent us from doing more later, if needed. Cheers Maurizio From brian.goetz at oracle.com Sat Jan 28 23:17:33 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Sat, 28 Jan 2023 18:17:33 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: <6ad45d5b-6a8e-4859-1c6b-02cfb486d53b@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> <6ad45d5b-6a8e-4859-1c6b-02cfb486d53b@oracle.com> Message-ID: Indeed.? The "return on complexity" (RoC) is weak at best. On 1/28/2023 4:49 PM, Maurizio Cimadamore wrote: > > On 28/01/2023 02:19, John Rose wrote: >> I must be missing your point here Maurizio? There is >> some corner case you are concerned with but I can?t see >> where the danger is. > > My point was not about "danger" but about "complex programming model", > and "return on complexity". Allowing initialization of local fields > before super() call would at the very least cause observable behavior > changes in all the instance initializers of the class (there was such > an example in the previous version of the JEP I believe). > > So my point was: why do we need to go there? That is not (anymore) > about allowing programs which were rejected for obtuse reasons. This > starts going down a path of messing with initialization order (e.g. > moving a field initializer, even if local, across the "super" call is > _not_ a compatible change). > > It maybe failure of imagination - but aside from pathological cases > (like classes whose initialization lets `this` escape - which I think > we all agree are on the bad side of the spectrum) I can't think of why > you would want to do that. The fact that the JVM allows it, and that > it does so in a sound fashion (which is what I'd expect the JVM to do) > is irrelevant in my consideration. > > To put it more clearly - it is quite clear as to why one might want to: > > * do validation on constructor parameter before a super call > * pass constructor parameter twice > * do some complex initialization which requires control flow > > These are things that add a net improvement on language > expressiveness, and do that with a very simple rule: you cannot spell > `this` before the super() call, which is easy to remember, and close > to what users would expect. > > To add the next bit, the model is: you cannot spell `this` except if > it's an initializer of a field. But wait, not any field, it has to be > a "local" field (this names is, btw, not great, as in Java I only know > about "local variables") - so that concept also comes with the ride. > Of course these concepts aren't hard to teach, but I think before we > go there we should have better arguments of _why_ we need to, as the > examples I've seen so far seem a bit on the thin side. And, doing the > points above doesn't prevent us from doing more later, if needed. > > Cheers > Maurizio > -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Sun Jan 29 22:14:01 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Sun, 29 Jan 2023 16:14:01 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <039c67d7-a622-29db-570c-54e306585908@oracle.com> <642a2b68-0b2c-9e1f-d12d-1c2ab3617ce6@oracle.com> <2be060c0-e42b-1ea0-c2df-68f70f12299c@oracle.com> Message-ID: On Fri, Jan 27, 2023 at 2:52 PM Archie Cobbs wrote: > JEP is updated . Not > surprisingly, it has gotten a good bit simpler. > FYI, I've added this additional detail: > (4) Replace the steps for constructor processing in ?12.5 with the > following: > > 1. Assign the arguments for the constructor to newly created parameter > variables for this constructor invocation. > 2. If this constructor contains an explicit constructor invocation > (?8.8.7.1), then execute the preceding BlockStatements, if any. > 3. If this constructor contains an explicit constructor invocation > (?8.8.7.1) of another constructor in the same class (using this), then > evaluate the arguments and process that constructor invocation recursively > using these same six steps. If that constructor invocation completes > abruptly, then this procedure completes abruptly for the same reason; > otherwise, continue with step 6. > 4. This constructor does not contain an explicit constructor > invocation of another constructor in the same class (using this). If > this constructor is for a class other than Object, then this > constructor contains an explicit or implicit invocation of a superclass > constructor (using super). Evaluate the arguments and process that > superclass constructor invocation recursively using these same six steps. > If that constructor invocation completes abruptly, then this procedure > completes abruptly for the same reason. Otherwise, continue with step 5. > 5. Execute the instance initializers and instance variable > initializers for this class, assigning the values of instance variable > initializers to the corresponding instance variables, in the left-to-right > order in which they appear textually in the source code for the class. If > execution of any of these initializers results in an exception, then no > further initializers are processed and this procedure completes abruptly > with that same exception. Otherwise, continue with step 6. > 6. Execute the rest of the body of this constructor. If that execution > completes abruptly, then this procedure completes abruptly for the same > reason. Otherwise, this procedure completes normally. > > The new step added is Step #2. Note that this means field initializers (and initialization blocks) execute after super() returns, which is the same as before but more interesting now that super() is no longer required to be first. Currently, there is an illusion of initializers executing at the "beginning" of the constructor. But in actuality, they have always actually executed after super() returns. Changing this wouldn't be backward compatible, and really there's no other option - they couldn't (for example) execute at the start of the constructor, because initializers are allowed to reference 'this' and assume the superclass is initialized. You can observe the current behavioral nuance if you're willing to e.g. (ab)use static fields: $ cat InitOrder1.java public class InitOrder1 { public static class Class1 { public Class1() { Class2.nextIndex++; // bad form here! } } public static class Class2 extends Class1 { static int nextIndex = 1; final int index = nextIndex; } public static void main(String[] args) { System.out.println(new Class2().index); } } $ javac InitOrder1.java && java InitOrder1 2 The changed JLS would open the window a little wider for oddities like this, to include the "static context" statements in a constructor prior to invoking super(). You still would have to jump through a static field or other tricks to observe the nuance though. Here's such an example: $ cat InitOrder2.java public class InitOrder2 { public static class Class1 { static int nextIndex = 1; final int index = nextIndex; public Class1() { nextIndex++; super(); } } public static void main(String[] args) { System.out.println(new Class1().index); } } $ javac InitOrder2.java && java InitOrder2 2 I think this falls into that category of things where the JLS has more detail in it than the corresponding programmer's mental model - and that's OK (see other discussion around switch patterns, instanceof, and primitive types). I don't think it's likely for a developer to be doing anything that would allow their mental model to be violated in this way, but of course it is possible if they try hard enough. -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Mon Jan 30 10:26:52 2023 From: redio.development at gmail.com (Red IO) Date: Mon, 30 Jan 2023 11:26:52 +0100 Subject: Constructor Interfaces In-Reply-To: References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> Message-ID: After exploring the world of annotation processors trying to implement test versions of the features, I discovered that annotation processors can't officially edit the ast and Lombok uses undocumented hacks to achieve this. This is a bit of a problem for implementing the test versions that way. My question is why is this disallowed? It would be a really powerful tool for compile time code execution/ generation. Great regards RedIODev On Wed, Jan 25, 2023, 20:19 Red IO wrote: > If the type information is an opt in feature it would not violate that > rule. Adding an erasing parameter would still be a non breaking change. But > if you opt in to request the type information and write logic depending on > that information then this is a braking change to the code anyway since the > logic wouldn't work with a raw type anyway. This could be another factor to > push away from utilizing raw types. It could be a keyword you add to a > parameterized thing to opt in (or implicitly opt in by utilizing the > extended type information) and in the same act disable the raw version for > it. Meaning that it would be a compile error to use the parameterized thing. > > Another option and preserve raw compatibility would be to exclude the > hidden parameter in a raw instance. The downside to this approach would be > that 2 signatures for every method/constructor that would otherwise include > the hidden parameter would be required. Also for generic classes there > would be 2 class layouts 1 with the hidden fields and 1 without. > > A completely different approach would be a static map of object instances > to parameter lists. This would require 0 changes in the class itself. But > in case of many generic objects loaded the performance of this approach is > likely catastrophic. Should be tested if proving viable though. Another > challenge is how a constructor would register the objects extended type > information without an extra parameter. Also this would be difficult to > implement for methods who are so short lived that the type parameter > registration would likely take as long as the method itself needs to > complete. > > Personally I would vote for braking with raw types (first approach) it > wouldn't harm existing code (since opt in), would provide the simplest (and > probably fastest) version and the only downside would be a harder and > braking transition for api which still use raw types and want to utilize > the extended type information (but as I already mentioned if an api wants > to opt in to extended type information on a class; having raw instances of > it would make absolutely no sense anyway). > > Great regards > RedIODev > > On Wed, Jan 25, 2023, 19:29 wrote: > >> [private] >> >> ------------------------------ >> >> *From: *"Red IO" >> *To: *"Remi Forax" >> *Cc: *"amber-dev" >> *Sent: *Wednesday, January 25, 2023 3:17:34 PM >> *Subject: *Re: Constructor Interfaces >> >> I proposed an idea (to Valhalla) to overcome type erasure that used the >> same idea of desugering and a hidden argument that carries the erased types >> class variable inside the generic context, but it was rejected as a to >> naive approach or something and they where "already working on different >> solutions for some time". >> >> >> What you have proposed is very similar to what Kotlin does, pass >> supplementary type arguments as parameter arguments/fields. >> This does not work, the Java spec explicitly says that adding type >> parameters, if there were previously none, is a backward compatible change >> but adding a supplementary parameter is not a backward compatible change >> (especially not a binary backward compatible change). >> >> That why the current proposed design pass the type arguments as a side >> channel not encoded in the type descriptor, see >> https://cr.openjdk.java.net/~jrose/values/parametric-vm.pdf >> >> regards, >> R?mi >> >> >> Great regards RedIODev >> >> On Wed, Jan 25, 2023, 14:51 Remi Forax wrote: >> >>> We may need something like this for Valhalla, when we will revisit how >>> to constraint the type arguments of universal generics. >>> >>> The kind of constraints you describe on type parameters already exist in >>> C# or TypeScript and was more recently introduced in Go, and there is the >>> type class of Haskell too. >>> >>> regards, >>> R?mi >>> >>> ------------------------------ >>> >>> *From: *"Red IO" >>> *To: *"amber-dev" >>> *Sent: *Wednesday, January 25, 2023 8:03:14 AM >>> *Subject: *Constructor Interfaces >>> >>> Summary >>> ------- >>> >>> Enable a parameterized class to constrain the parameterized type to be >>> constructible with a given list of parameters. >>> >>> >>> >>> Motivation >>> ---------- >>> >>> It is possible since JDK 8 to get a constructor (method) reference of an >>> object. This allowed for the creation of an unknown class with a known >>> constructor reference. But currently the only way to obtain such reference >>> is at call site like this: >>> Box stringBox = new Box<>(String::new); >>> >>> It is inconvenient for the user to supply the the reference themselves >>> and can confuse them as the type of the parameter is something like >>> Supplier which doesn't require the pased reference to be a >>> constructor. >>> It also clutters api's like "toArray" which requires an IntFunction to >>> be type safe. >>> >>> Description >>> ----------- >>> >>> ConstructorInterface >>> A ConstructorInterface is a special kind of interface similar to a >>> FunctionalInterface. It also has similar constraints. It only allows >>> abstract constructors and no other abstract methods. It can declare >>> multiple constructors though. The definition of such interface would look >>> similar to this: >>> >>> @ConstructorInterface //optional validation like FunctionalInterfaces >>> public interface DefaultConstructible { >>> new(); >>> new(char[] chars); >>> } >>> >>> A parameterized type could declare this interface as a type bound for >>> its parameter and therefore enabling it to be constructed safely. Like this: >>> public class Box { >>> public Box() { >>> E newElement = new E(); >>> } >>> } >>> The containing type is not forced to implement the ContructorInterface >>> explicitly. It is implicitly implemented if the required constructor(s) >>> is(are) present. >>> public static void main(String[] args) { >>> Box stringBox = new Box<>(); //compiles because String has the >>> required constructors. >>> Box dateBox new Box<>(); error: java.sql.Data does not >>> satisfy the type bound DefaultConstructible >>> } >>> The interface might not be implemented by any class, since it doesn't >>> follow the inheritance rule that extending classes of those who implement >>> it also implement it. This requirement comes from the fact that extending >>> classes do not necessarily need to have the same constructor signature and >>> therefore don't qualify the requirements for the interface. Another option >>> would be that extending classes of classes that implement a constructor >>> interface explicitly are also required to supply the necessary constructors. >>> >>> class Foo implements DefaultConstructable { >>> //both required by the interface >>> public Foo() {} >>> public Foo(char[] chars) {} >>> } >>> >>> class Bar extends Foo { >>> //the requirement for the required constructors is passed down. >>> public Bar() {} >>> public Bar(char[] chars) {} >>> } >>> >>> >>> >>> public static T createT() { >>> return new T(); >>> } >>> >>> public T wrapper() { >>> return createT(); >>> } >>> This would technically work but would require a lot of static analysis >>> to find the real type of T to call its constructor. >>> Restricting the use of "new T()" to type parameters that specify a >>> constructor interface directly and only allow those to be resolved with a >>> concrete type rather than another type parameter. >>> >>> Alternatives >>> ------------ >>> An alternative would be to introduce new syntax to restrict the ability >>> of certain constructors on a parameter type. Like c# does (but only for the >>> default constructor) : >>> public static T foo() where T: new() { >>> return new T(); >>> } >>> In java: >>> public static T foo() { >>> return new T(); >>> } >>> The downside of this approach is obviously the introduction of new >>> syntax rather than reusing the interface/inheritance syntax. >>> >>> Another alternative to this approach could be to implement static >>> abstract methods. This would allow an interface to mandate a static Factory >>> Method. The downside of this approach is that it requires the parameter >>> class to actually implement the interface and the concept of type erasure >>> would need to be addressed for static abstract methods to work. In contrast >>> the ConstructorInterface enables every class that matches its contract to >>> pass the type bound. >>> >>> >>> >>> Risks and Assumptions >>> --------------------- >>> >>> As mentioned before the restriction the interface is giving on a type >>> bound is different to normal interfaces, it restricts by its containing >>> abstract constructors not by the type itself. It also makes use of the new >>> operator on type variables. >>> >>> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From ron.pressler at oracle.com Mon Jan 30 13:37:20 2023 From: ron.pressler at oracle.com (Ron Pressler) Date: Mon, 30 Jan 2023 13:37:20 +0000 Subject: Constructor Interfaces In-Reply-To: References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> Message-ID: <8D24A48B-5AC4-461A-9A5A-40E9F201DE0E@oracle.com> > On 30 Jan 2023, at 10:26, Red IO wrote: > > After exploring the world of annotation processors trying to implement test versions of the features, I discovered that annotation processors can't officially edit the ast and Lombok uses undocumented hacks to achieve this. This is a bit of a problem for implementing the test versions that way. My question is why is this disallowed? It would be a really powerful tool for compile time code execution/ generation. > Great regards > RedIODev It is disallowed because it would allow compiler plugins to change the semantics of Java code, adding, in effect, AST macros. Macros are very useful and very harmful. Some languages decide to allow them, Java forbids them. As with any feature, the question we ask is not ?is it useful?? but ?does its contribution significantly outweigh all of its costs and downsides in the long term for Java?s core audience?" Note that the classes Lombok uses are not only undocumented, but also unexported, which makes any code breaking open the JDK?s encapsulation to rely on them not portable across Java versions. Also note that the most important exploration of language features is the one required to establish that they?re necessary. Implementing a language feature is usually very easy and often not particularly interesting; what?s hard is finding the right problem to solve. A more valuable exploration of your proposed feature wouldn?t be implementing it, but analysing codebases to measure the importance of the problem. ? Ron From forax at univ-mlv.fr Mon Jan 30 14:02:29 2023 From: forax at univ-mlv.fr (forax at univ-mlv.fr) Date: Mon, 30 Jan 2023 15:02:29 +0100 (CET) Subject: Constructor Interfaces In-Reply-To: <8D24A48B-5AC4-461A-9A5A-40E9F201DE0E@oracle.com> References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> <8D24A48B-5AC4-461A-9A5A-40E9F201DE0E@oracle.com> Message-ID: <111024247.8809167.1675087349632.JavaMail.zimbra@u-pem.fr> ----- Original Message ----- > From: "Ron Pressler" > To: "Red IO" > Cc: "Remi Forax" , "amber-dev" > Sent: Monday, January 30, 2023 2:37:20 PM > Subject: Re: Constructor Interfaces >> On 30 Jan 2023, at 10:26, Red IO wrote: >> >> After exploring the world of annotation processors trying to implement test >> versions of the features, I discovered that annotation processors can't >> officially edit the ast and Lombok uses undocumented hacks to achieve this. >> This is a bit of a problem for implementing the test versions that way. My >> question is why is this disallowed? It would be a really powerful tool for >> compile time code execution/ generation. >> Great regards >> RedIODev > > It is disallowed because it would allow compiler plugins to change the semantics > of Java code, adding, in effect, AST macros. Macros are very useful and very > harmful. Some languages decide to allow them, Java forbids them. As with any > feature, the question we ask is not ?is it useful?? but ?does its contribution > significantly outweigh all of its costs and downsides in the long term for > Java?s core audience?" > > Note that the classes Lombok uses are not only undocumented, but also > unexported, which makes any code breaking open the JDK?s encapsulation to rely > on them not portable across Java versions. > > Also note that the most important exploration of language features is the one > required to establish that they?re necessary. Implementing a language feature > is usually very easy and often not particularly interesting; what?s hard is > finding the right problem to solve. A more valuable exploration of your > proposed feature wouldn?t be implementing it, but analysing codebases to > measure the importance of the problem. Also the bytecode (the class file format) is the documented AST. Modifying the bytecode means that your code works for Java but also Kotlin and Scala. This can be done on top of an annotations processor like Quarkus does. But obviously, you can not change the API, just implement backward compatible modifications (if separate compilation is a concern). > > ? Ron R?mi From brian.goetz at oracle.com Mon Jan 30 14:36:36 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 30 Jan 2023 09:36:36 -0500 Subject: Constructor Interfaces In-Reply-To: References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> Message-ID: <12ef0967-607d-d644-44ef-6d049d1696c1@oracle.com> Annotations are exactly as (not) powerful as they were designed to be.? JSR 175 (https://www.jcp.org/en/jsr/detail?id=175) -- the effort that gave us annotations -- is called a _metadata facility for the Java Language_, not a _metaprogramming facility_.? This choice was not made because the leaders of that effort were ignorant about metaprogramming; the goal was to leave interpretation of annotations to things like service containers, test frameworks, etc, because annotations are too weak a mechanism for providing language semantics. As Ron pointed out, it is a very common mistake when imagining possible language features to focus only on "if I had X, what cool code could I write?", and ignore the "if everyone had X, what would be the effect on readability, reliability, and maintainability of the global codebase?"? But understanding the latter is where much of the challenge lies in responsibly evolving a language. On 1/30/2023 5:26 AM, Red IO wrote: > After exploring the world of annotation processors trying to implement > test versions of the features, I discovered that annotation processors > can't officially edit the ast and Lombok uses undocumented hacks to > achieve this. This is a bit of a problem for implementing the test > versions that way. My question is why is this disallowed? It would be > a really powerful tool for compile time code execution/ generation. > Great regards > RedIODev > > On Wed, Jan 25, 2023, 20:19 Red IO wrote: > > If the type information is an opt in feature it would not violate > that rule. Adding an erasing parameter would still be a non > breaking change. But if you opt in to request the type information > and write logic depending on that information then this is a > braking change to the code anyway since the logic wouldn't work > with a raw type anyway. This could be another factor to push away > from utilizing raw types. It could be a keyword you add to a > parameterized thing to opt in (or implicitly opt in by utilizing > the extended type information) and in the same act disable the raw > version for it. Meaning that it would be a compile error to use > the parameterized thing. > > Another option and preserve raw compatibility would be to exclude > the hidden parameter in a raw instance. The downside to this > approach would be that 2 signatures for every method/constructor > that would otherwise include the hidden parameter would be > required. Also for generic classes there would be 2 class layouts > 1 with the hidden fields and 1 without. > > A completely different approach would be a static map of object > instances to parameter lists. This would require 0 changes in the > class itself. But in case of many generic objects loaded the > performance of this approach is likely catastrophic. Should be > tested if proving viable though. Another challenge is how a > constructor would register the objects extended type information > without an extra parameter. Also this would be difficult to > implement for methods who are so short lived that the type > parameter registration would likely take as long as the method > itself needs to complete. > > Personally I would vote for braking with raw types (first > approach) it wouldn't harm existing code (since opt in), would > provide the simplest (and probably fastest) version and the only > downside would be a harder and braking transition for api which > still use raw types and want to utilize the extended type > information (but as I already mentioned if an api wants to opt in > to extended type information on a class; having raw instances of > it would make absolutely no sense anyway). > > Great regards > RedIODev > > On Wed, Jan 25, 2023, 19:29 wrote: > > [private] > > ------------------------------------------------------------------------ > > *From: *"Red IO" > *To: *"Remi Forax" > *Cc: *"amber-dev" > *Sent: *Wednesday, January 25, 2023 3:17:34 PM > *Subject: *Re: Constructor Interfaces > > I proposed an idea (to Valhalla) to overcome type erasure > that used the same idea of desugering and a hidden > argument that carries the erased types class variable > inside the generic context, but it was rejected as a to > naive approach or something and they where "already > working on different solutions for some time". > > > What you have proposed is very similar to what Kotlin does, > pass supplementary type arguments as parameter arguments/fields. > This does not work, the Java spec explicitly says that adding > type parameters, if there were previously none, is a backward > compatible change but adding a supplementary parameter is not > a backward compatible change (especially not a binary backward > compatible change). > > That why the current proposed design pass the type arguments > as a side channel not encoded in the type descriptor, see > https://cr.openjdk.java.net/~jrose/values/parametric-vm.pdf > > regards, > R?mi > > > Great regards RedIODev > > On Wed, Jan 25, 2023, 14:51 Remi Forax > wrote: > > We may need something like this for Valhalla, when we > will revisit how to constraint the type arguments of > universal generics. > > The kind of constraints you describe?on type > parameters already exist in C# or TypeScript and was > more recently introduced in Go, and there is the type > class of Haskell too. > > regards, > R?mi > > ------------------------------------------------------------------------ > > *From: *"Red IO" > *To: *"amber-dev" > *Sent: *Wednesday, January 25, 2023 8:03:14 AM > *Subject: *Constructor Interfaces > > Summary > ------- > > Enable a parameterized class to constrain the > parameterized type to be constructible with a > given list of parameters. > > > > Motivation > ---------- > > It is possible since JDK 8 to get a constructor > (method) reference of an object. This allowed for > the creation of an unknown class with a known > constructor reference. But currently the only way > to obtain such reference is at call site like this: > Box stringBox = new Box<>(String::new); > > It is inconvenient for the user to supply the the > reference themselves and can confuse them as the > type of the parameter is something like > Supplier which doesn't require the pased > reference to be a constructor. > It also clutters api's like "toArray" which > requires an IntFunction to be type safe. > > Description > ----------- > > ConstructorInterface > A ConstructorInterface is a special kind of > interface similar to a FunctionalInterface. It > also has similar constraints. It only allows > abstract constructors and no other abstract > methods. It can declare multiple constructors > though. The definition of such interface would > look similar to this: > > @ConstructorInterface //optional validation like > FunctionalInterfaces > public interface DefaultConstructible { > new(); > new(char[] chars); > } > > A parameterized type could declare this interface > as a type bound for its parameter and therefore > enabling it to be constructed safely. Like this: > public class Box { > public Box() { > E newElement = new E(); > } > } > The containing type is not forced to implement the > ContructorInterface explicitly. It is implicitly > implemented if the required constructor(s) is(are) > present. > public static void main(String[] args) { > Box stringBox = new Box<>(); //compiles > because String has the required constructors. > Box dateBox new Box<>(); error: > java.sql.Data does not satisfy the type bound > DefaultConstructible > } > The interface might not be implemented by any > class, since it doesn't follow the inheritance > rule that extending classes of those who implement > it also implement it. This requirement comes from > the fact that extending classes do not necessarily > need to have the same constructor signature and > therefore don't qualify the requirements for the > interface. Another option would be that extending > classes of classes that implement a constructor > interface explicitly are also required to supply > the necessary constructors. > > class Foo implements DefaultConstructable { > //both required by the interface > public Foo() {} > public Foo(char[] chars) {} > } > > class Bar extends Foo { > //the requirement for the required constructors is > passed down. > public Bar() {} > public Bar(char[] chars) {} > } > > > > public static T createT() { > return?new T(); > } > > public T wrapper() { > return createT(); > } > This would technically work but would require a > lot of static analysis to find the real type of T > to call its constructor. > Restricting the use of "new T()" to type > parameters that specify a constructor interface > directly and only allow those to be resolved with > a concrete type rather than another type parameter. > > Alternatives > ------------ > An alternative would be to introduce new syntax to > restrict the ability of certain constructors on a > parameter type. Like c# does (but only for the > default constructor) : > public static T foo() where T: new() { > return new T(); > } > In java: > public static T foo() { > return new T(); > } > The downside of this approach is obviously the > introduction of new syntax rather than reusing the > interface/inheritance syntax. > > Another alternative to this approach could be to > implement static abstract methods. This would > allow an interface to mandate a static Factory > Method. The downside of this approach is that it > requires the parameter class to actually implement > the interface and the concept of type erasure > would need to be addressed for static abstract > methods to work. In contrast the > ConstructorInterface enables every class that > matches its contract to pass the type bound. > > > > Risks and Assumptions > --------------------- > > As mentioned before the restriction the interface > is giving on a type bound is different to normal > interfaces, it restricts by its containing > abstract constructors not by the type itself. It > also makes use of the new operator on type variables. > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From redio.development at gmail.com Mon Jan 30 14:36:59 2023 From: redio.development at gmail.com (Red IO) Date: Mon, 30 Jan 2023 15:36:59 +0100 Subject: Constructor Interfaces In-Reply-To: <8D24A48B-5AC4-461A-9A5A-40E9F201DE0E@oracle.com> References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> <8D24A48B-5AC4-461A-9A5A-40E9F201DE0E@oracle.com> Message-ID: The idea behind implementing it quick and dirty with "Marcos"(annotation processors) was to see applicability and usefulness of the features. I think it's really difficult to either write synthetic examples or develop libraries with the feature in mind while it's not working showing red lines everywhere and having neither syntax highlighting nor the ability to compile everything. But I got an idea even though not optimal that allows me to implement a prototype in bounds of normal annotation processing (and new class creation). And I think the bigger feature aka runtime generics are undoubtedly generally understood to be highly desirable. Great regards RedIODev On Mon, Jan 30, 2023, 14:37 Ron Pressler wrote: > > > > On 30 Jan 2023, at 10:26, Red IO wrote: > > > > After exploring the world of annotation processors trying to implement > test versions of the features, I discovered that annotation processors > can't officially edit the ast and Lombok uses undocumented hacks to achieve > this. This is a bit of a problem for implementing the test versions that > way. My question is why is this disallowed? It would be a really powerful > tool for compile time code execution/ generation. > > Great regards > > RedIODev > > It is disallowed because it would allow compiler plugins to change the > semantics of Java code, adding, in effect, AST macros. Macros are very > useful and very harmful. Some languages decide to allow them, Java forbids > them. As with any feature, the question we ask is not ?is it useful?? but > ?does its contribution significantly outweigh all of its costs and > downsides in the long term for Java?s core audience?" > > Note that the classes Lombok uses are not only undocumented, but also > unexported, which makes any code breaking open the JDK?s encapsulation to > rely on them not portable across Java versions. > > Also note that the most important exploration of language features is the > one required to establish that they?re necessary. Implementing a language > feature is usually very easy and often not particularly interesting; what?s > hard is finding the right problem to solve. A more valuable exploration of > your proposed feature wouldn?t be implementing it, but analysing codebases > to measure the importance of the problem. > > ? Ron -------------- next part -------------- An HTML attachment was scrubbed... URL: From brian.goetz at oracle.com Mon Jan 30 14:49:43 2023 From: brian.goetz at oracle.com (Brian Goetz) Date: Mon, 30 Jan 2023 09:49:43 -0500 Subject: Loosening requirements for super() invocation In-Reply-To: References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> Message-ID: <32640417-e740-8242-147f-3175ffa633d6@oracle.com> This is a first stab, but I think this may be the extent of the spec changes for this JEP: > 8.8.7 Constructor Body > The first statement of a constructor body may be an explicit > invocation of another > constructor of the same class or of the direct superclass (?8.8.7.1). A constructor body _may contain_ an explicit invocation... > ConstructorBody: > { [ExplicitConstructorInvocation] [BlockStatements] } ConstructorBody: ? { [BlockStatements] [ExplicitConstructorInvocation] [BlockStatements] } > It is a compile-time error for a constructor to directly or indirectly > invoke itself > through a series of one or more explicit constructor invocations > involving this. > If a constructor body does not begin with an explicit constructor > invocation and does not contain an explicit constructor invocation > the constructor being declared is not part of the primordial class > Object, then > the constructor body implicitly begins with a superclass constructor > invocation > "super();", an invocation of the constructor of its direct superclass > that takes no > arguments. > Except for the possibility of explicit constructor invocations, and > the prohibition > on explicitly returning a value (?14.17), the body of a constructor is > like the body > of a method (?8.4.7). > A return statement (?14.17) may be used in the body of a constructor > if it does > not include an expression. If a constructor body contains an explicit constructor invocation, the BlockStatements preceding the explicit constructor invocation are called the _prologue_ of the constructor body, and the BlockStatements following the explicit constructor invocation are called the _main body_ of the constructor.? A return statement may be used in the main body of a constructor if it does not include an expression.? It is a compile-time error if a return statement appears in the prologue of the constructor body. > 8.8.7.1 Explicit Constructor Invocations > An explicit constructor invocation statement introduces a static > context (?8.1.3), which includes the prologue of the constructor and the explicit constructor invocation statement, > which limits the use of constructs that refer to the current object. > Notably, the > keywords this and super are prohibited in a static context (?15.8.3, > ?15.11.2), > as are unqualified references to instance variables, instance methods, > and type > parameters of lexically enclosing declarations (?6.5.5.1, ?6.5.6.1, > ?15.12.3). Additionally, as you point out, there are some corresponding changes in 12.5.? Your list is a good start, I'd amplify as: > 1. If this constructor contains an explicit constructor invocation > (?8.8.7.1), then execute the preceding |BlockStatements|, if any. > If this constructor contains an explicit constructor invocation, then execute the BlockStatements of the prologue of the constructor body.? If execution of any statement completes abruptly, then execution of the constructor completes abruptly for the same reason. On 1/28/2023 11:03 AM, Archie Cobbs wrote: > On Fri, Jan 27, 2023 at 8:19 PM John Rose wrote: > > On 26 Jan 2023, at 11:19, Maurizio Cimadamore wrote: > > On 26/01/2023 18:16, Archie Cobbs wrote: > > Yes, but for this to happen the subclass would have to be > in effect intentionally subverting the superclass constructor. > > In other words, a problem like you describe can't suddenly > just start happening "by accident" just because this new > feature exists... > > Well, you could have a subclass (in some client jar) which > "subverts" as you say, some superclass in a library. Perhaps > the library was not prepared for that kind of behavior, and > now there's a new bug. > > IMHO, we should try to stay well clear of that can of worms. > It's not like we have to open it now either - the other things > you propose are 100% non-controversial. > > Just to be clear: > > Early assignment to a /super/ field is never possible > > > Ah, you are correct. I was missing this nuance and incorrectly > thinking it was allowed to write to *any* field in the object prior to > super(). > > JVMS ?4.10.2.4 > : > > Before that method invokes another instance initialization method > of |myClass| or its direct superclass on |this|, the only > operation the method can perform on |this| is assigning fields > *declared within |myClass|*. > > > So that whole discussion about writing to superclass fields prior to > super() is moot. > > I must be missing your point here Maurizio? There is > some corner case you are concerned with but I can?t see > where the danger is. > > > Yes... and now me too :) > > -Archie > > -- > Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From archie.cobbs at gmail.com Mon Jan 30 15:48:29 2023 From: archie.cobbs at gmail.com (Archie Cobbs) Date: Mon, 30 Jan 2023 09:48:29 -0600 Subject: Loosening requirements for super() invocation In-Reply-To: <32640417-e740-8242-147f-3175ffa633d6@oracle.com> References: <19a9358c-fc8d-8ea0-9f4f-907cf65f0c52@oracle.com> <7fac1166-3f96-e88a-8715-f7679f9eb28b@oracle.com> <6912abf7-8fdf-3b28-0288-ba8c3f876394@oracle.com> <3D6F831F-A228-401B-8199-BE4DC146CE86@oracle.com> <32640417-e740-8242-147f-3175ffa633d6@oracle.com> Message-ID: On Mon, Jan 30, 2023 at 8:49 AM Brian Goetz wrote: > This is a first stab, but I think this may be the extent of the spec > changes for this JEP: > Thanks Brian! This is very helpful. I've incorporated these and updated the draft. FYI I tweaked your wording to ensure that "main body" is also defined in the case of a constructor with no explicit invocation (required so they can "return" as well). -Archie -- Archie L. Cobbs -------------- next part -------------- An HTML attachment was scrubbed... URL: From joe.darcy at oracle.com Tue Jan 31 03:18:44 2023 From: joe.darcy at oracle.com (Joseph D. Darcy) Date: Mon, 30 Jan 2023 19:18:44 -0800 Subject: Constructor Interfaces In-Reply-To: <12ef0967-607d-d644-44ef-6d049d1696c1@oracle.com> References: <1004124830.5064580.1674654700465.JavaMail.zimbra@u-pem.fr> <2130817602.5292556.1674671346470.JavaMail.zimbra@u-pem.fr> <12ef0967-607d-d644-44ef-6d049d1696c1@oracle.com> Message-ID: <0f801d76-aa07-a85d-2935-b0f245bc1e92@oracle.com> To add to what Brian and others have said on this thread, annotation processors as first shipped in JDK 5.0 with apt and later standardized through JSR 269 in Java SE 6 were intentionally designed to *not* allow direct modification of ASTs to avoid language fragmentation, etc. However, it was acknowledged that at least some subset of the ability to modify sources was useful so annotation processors supported the ability to generate missing subclasses and *superclasses* during processing. Those capabilities are sufficient to implement a properties-like scheme, as sketched out in this blog entry: https://web.archive.org/web/20100410203408/http://blogs.sun.com/darcy/entry/properties_via_annotation_processing and later productized in projects like: http://immutables.github.io/immutable.html HTH, -Joe On 1/30/2023 6:36 AM, Brian Goetz wrote: > Annotations are exactly as (not) powerful as they were designed to > be.? JSR 175 (https://www.jcp.org/en/jsr/detail?id=175) -- the effort > that gave us annotations -- is called a _metadata facility for the > Java Language_, not a _metaprogramming facility_.? This choice was not > made because the leaders of that effort were ignorant about > metaprogramming; the goal was to leave interpretation of annotations > to things like service containers, test frameworks, etc, because > annotations are too weak a mechanism for providing language semantics. > > As Ron pointed out, it is a very common mistake when imagining > possible language features to focus only on "if I had X, what cool > code could I write?", and ignore the "if everyone had X, what would be > the effect on readability, reliability, and maintainability of the > global codebase?"? But understanding the latter is where much of the > challenge lies in responsibly evolving a language. > > > > > > On 1/30/2023 5:26 AM, Red IO wrote: >> After exploring the world of annotation processors trying to >> implement test versions of the features, I discovered that annotation >> processors can't officially edit the ast and Lombok uses undocumented >> hacks to achieve this. This is a bit of a problem for implementing >> the test versions that way. My question is why is this disallowed? It >> would be a really powerful tool for compile time code execution/ >> generation. >> Great regards >> RedIODev >> >> On Wed, Jan 25, 2023, 20:19 Red IO wrote: >> >> If the type information is an opt in feature it would not violate >> that rule. Adding an erasing parameter would still be a non >> breaking change. But if you opt in to request the type >> information and write logic depending on that information then >> this is a braking change to the code anyway since the logic >> wouldn't work with a raw type anyway. This could be another >> factor to push away from utilizing raw types. It could be a >> keyword you add to a parameterized thing to opt in (or implicitly >> opt in by utilizing the extended type information) and in the >> same act disable the raw version for it. Meaning that it would be >> a compile error to use the parameterized thing. >> >> Another option and preserve raw compatibility would be to exclude >> the hidden parameter in a raw instance. The downside to this >> approach would be that 2 signatures for every method/constructor >> that would otherwise include the hidden parameter would be >> required. Also for generic classes there would be 2 class layouts >> 1 with the hidden fields and 1 without. >> >> A completely different approach would be a static map of object >> instances to parameter lists. This would require 0 changes in the >> class itself. But in case of many generic objects loaded the >> performance of this approach is likely catastrophic. Should be >> tested if proving viable though. Another challenge is how a >> constructor would register the objects extended type information >> without an extra parameter. Also this would be difficult to >> implement for methods who are so short lived that the type >> parameter registration would likely take as long as the method >> itself needs to complete. >> >> Personally I would vote for braking with raw types (first >> approach) it wouldn't harm existing code (since opt in), would >> provide the simplest (and probably fastest) version and the only >> downside would be a harder and braking transition for api which >> still use raw types and want to utilize the extended type >> information (but as I already mentioned if an api wants to opt in >> to extended type information on a class; having raw instances of >> it would make absolutely no sense anyway). >> >> Great regards >> RedIODev >> >> On Wed, Jan 25, 2023, 19:29 wrote: >> >> [private] >> >> ------------------------------------------------------------------------ >> >> *From: *"Red IO" >> *To: *"Remi Forax" >> *Cc: *"amber-dev" >> *Sent: *Wednesday, January 25, 2023 3:17:34 PM >> *Subject: *Re: Constructor Interfaces >> >> I proposed an idea (to Valhalla) to overcome type erasure >> that used the same idea of desugering and a hidden >> argument that carries the erased types class variable >> inside the generic context, but it was rejected as a to >> naive approach or something and they where "already >> working on different solutions for some time". >> >> >> What you have proposed is very similar to what Kotlin does, >> pass supplementary type arguments as parameter arguments/fields. >> This does not work, the Java spec explicitly says that adding >> type parameters, if there were previously none, is a backward >> compatible change but adding a supplementary parameter is not >> a backward compatible change (especially not a binary >> backward compatible change). >> >> That why the current proposed design pass the type arguments >> as a side channel not encoded in the type descriptor, see >> https://cr.openjdk.java.net/~jrose/values/parametric-vm.pdf >> >> regards, >> R?mi >> >> >> Great regards RedIODev >> >> On Wed, Jan 25, 2023, 14:51 Remi Forax >> wrote: >> >> We may need something like this for Valhalla, when we >> will revisit how to constraint the type arguments of >> universal generics. >> >> The kind of constraints you describe?on type >> parameters already exist in C# or TypeScript and was >> more recently introduced in Go, and there is the type >> class of Haskell too. >> >> regards, >> R?mi >> >> ------------------------------------------------------------------------ >> >> *From: *"Red IO" >> *To: *"amber-dev" >> *Sent: *Wednesday, January 25, 2023 8:03:14 AM >> *Subject: *Constructor Interfaces >> >> Summary >> ------- >> >> Enable a parameterized class to constrain the >> parameterized type to be constructible with a >> given list of parameters. >> >> >> >> Motivation >> ---------- >> >> It is possible since JDK 8 to get a constructor >> (method) reference of an object. This allowed for >> the creation of an unknown class with a known >> constructor reference. But currently the only way >> to obtain such reference is at call site like this: >> Box stringBox = new Box<>(String::new); >> >> It is inconvenient for the user to supply the the >> reference themselves and can confuse them as the >> type of the parameter is something like >> Supplier which doesn't require the pased >> reference to be a constructor. >> It also clutters api's like "toArray" which >> requires an IntFunction to be type safe. >> >> Description >> ----------- >> >> ConstructorInterface >> A ConstructorInterface is a special kind of >> interface similar to a FunctionalInterface. It >> also has similar constraints. It only allows >> abstract constructors and no other abstract >> methods. It can declare multiple constructors >> though. The definition of such interface would >> look similar to this: >> >> @ConstructorInterface //optional validation like >> FunctionalInterfaces >> public interface DefaultConstructible { >> new(); >> new(char[] chars); >> } >> >> A parameterized type could declare this interface >> as a type bound for its parameter and therefore >> enabling it to be constructed safely. Like this: >> public class Box { >> public Box() { >> E newElement = new E(); >> } >> } >> The containing type is not forced to implement >> the ContructorInterface explicitly. It is >> implicitly implemented if the required >> constructor(s) is(are) present. >> public static void main(String[] args) { >> Box stringBox = new Box<>(); //compiles >> because String has the required constructors. >> Box dateBox new Box<>(); error: >> java.sql.Data does not satisfy the type bound >> DefaultConstructible >> } >> The interface might not be implemented by any >> class, since it doesn't follow the inheritance >> rule that extending classes of those who >> implement it also implement it. This requirement >> comes from the fact that extending classes do not >> necessarily need to have the same constructor >> signature and therefore don't qualify the >> requirements for the interface. Another option >> would be that extending classes of classes that >> implement a constructor interface explicitly are >> also required to supply the necessary constructors. >> >> class Foo implements DefaultConstructable { >> //both required by the interface >> public Foo() {} >> public Foo(char[] chars) {} >> } >> >> class Bar extends Foo { >> //the requirement for the required constructors >> is passed down. >> public Bar() {} >> public Bar(char[] chars) {} >> } >> >> >> >> public static T createT() { >> return?new T(); >> } >> >> public T wrapper() { >> return createT(); >> } >> This would technically work but would require a >> lot of static analysis to find the real type of T >> to call its constructor. >> Restricting the use of "new T()" to type >> parameters that specify a constructor interface >> directly and only allow those to be resolved with >> a concrete type rather than another type parameter. >> >> Alternatives >> ------------ >> An alternative would be to introduce new syntax >> to restrict the ability of certain constructors >> on a parameter type. Like c# does (but only for >> the default constructor) : >> public static T foo() where T: new() { >> return new T(); >> } >> In java: >> public static T foo() { >> return new T(); >> } >> The downside of this approach is obviously the >> introduction of new syntax rather than reusing >> the interface/inheritance syntax. >> >> Another alternative to this approach could be to >> implement static abstract methods. This would >> allow an interface to mandate a static Factory >> Method. The downside of this approach is that it >> requires the parameter class to actually >> implement the interface and the concept of type >> erasure would need to be addressed for static >> abstract methods to work. In contrast the >> ConstructorInterface enables every class that >> matches its contract to pass the type bound. >> >> >> >> Risks and Assumptions >> --------------------- >> >> As mentioned before the restriction the interface >> is giving on a type bound is different to normal >> interfaces, it restricts by its containing >> abstract constructors not by the type itself. It >> also makes use of the new operator on type >> variables. >> >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: