-
Notifications
You must be signed in to change notification settings - Fork 5.8k
8199318: add idempotent copy operation for Map.Entry #4295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
8199318: add idempotent copy operation for Map.Entry #4295
Conversation
👋 Welcome back smarks! A progress list of the required criteria for merging this PR into |
@stuart-marks The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
/csr |
@stuart-marks has indicated that a compatibility and specification (CSR) request is needed for this pull request. |
Webrevs
|
LGTM, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I read through the javadoc and API notes and it all looks reasonable.
A quick search reveals that Guava has a public subclass of SimpleImmutableEntry: https://guava.dev/releases/30.1.1-jre/api/docs/com/google/common/cache/RemovalNotification.html There are possibly others. It doesn't seem worth the incompatibility to me, as it would break stuff in order to have only a "cleaner" meaning for "immutable." Also, there are other classes in the JDK that claim they are immutable but which can be subclassed, e.g., BigInteger. I don't see a good way of fixing this. |
Thanks, i've done some digging too, So documenting the existing behavior seems the only possible way. |
@@ -393,9 +393,9 @@ | |||
Set<Map.Entry<K, V>> entrySet(); | |||
|
|||
/** | |||
* A map entry (key-value pair). The entry may be unmodifiable, or the | |||
* A map entry (key-value pair). The Entry may be unmodifiable, or the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In that case then maybe it should be {@code Entry}
in both places where entry
was replaced with Entry
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe. We're not terribly consistent about this. A fair amount of the docs just uses a plain-text, capitalized form of a class name, as opposed to the code font. Using the code font everywhere adds clutter to both the markup and to the rendered output. In this case I wanted to distinguish the generic mention of an entry in a map from an instance of an Entry object. In cases where it needs to be absolutely clear, I used Map.Entry
(the qualified name, in code font). Doing that here seems like it would add too much clutter though.
Mailing list message from Peter Levart on core-libs-dev: On 02/06/2021 19:24, R?mi Forax wrote:
There's nothing wrong in subclassing an immutable class. As long as the Peter |
@stuart-marks This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 96 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Mailing list message from Remi Forax on core-libs-dev: ----- Mail original -----
It has to be immutable all the way up, you have the same issue if the subclass is not final. If you filter out guava an google cache, github get you 12 pages of result and only one stupid code A lot of code uses SimpleImmutableEntry as a pair, my hope is that the introduction of records will clean that practice. That said, there is also several broken codes, mostly two issues, I kind of regret that the compiler does not provide automatically an implementation of compareTo if the record implements Comparable.
R?mi |
1 similar comment
Mailing list message from Remi Forax on core-libs-dev: ----- Mail original -----
It has to be immutable all the way up, you have the same issue if the subclass is not final. If you filter out guava an google cache, github get you 12 pages of result and only one stupid code A lot of code uses SimpleImmutableEntry as a pair, my hope is that the introduction of records will clean that practice. That said, there is also several broken codes, mostly two issues, I kind of regret that the compiler does not provide automatically an implementation of compareTo if the record implements Comparable.
R?mi |
Mailing list message from John Rose on core-libs-dev: On Jun 3, 2021, at 12:46 PM, Remi Forax <forax at univ-mlv.fr<mailto:forax at univ-mlv.fr>> wrote: I kind of regret that the compiler does not provide automatically an implementation of compareTo if the record implements Comparable. That?s a slippery slope. IIRC we consciously stopped That said, there are other ways to fix this. We should interface ComparableRecord<T extends Record & ComparableRecord<T>> record Foo(int x, String y) implements ComparableRecord<Foo> { ? } http://cr.openjdk.java.net/~jrose/draft/ComparableRecord.java ? John |
1 similar comment
Mailing list message from John Rose on core-libs-dev: On Jun 3, 2021, at 12:46 PM, Remi Forax <forax at univ-mlv.fr<mailto:forax at univ-mlv.fr>> wrote: I kind of regret that the compiler does not provide automatically an implementation of compareTo if the record implements Comparable. That?s a slippery slope. IIRC we consciously stopped That said, there are other ways to fix this. We should interface ComparableRecord<T extends Record & ComparableRecord<T>> record Foo(int x, String y) implements ComparableRecord<Foo> { ? } http://cr.openjdk.java.net/~jrose/draft/ComparableRecord.java ? John |
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
The main issue with this kind of code is that the JIT does not see through the ClassValue. Tweaking a little bit your code, I get import java.util.ArrayList; @SuppressWarnings({"rawtypes","unchecked"}) static void main(String[] args) { var list = Stream.of(new Foo(2, "foo"), new Foo(2, "bar")) .sorted().toList();
|
1 similar comment
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
The main issue with this kind of code is that the JIT does not see through the ClassValue. Tweaking a little bit your code, I get import java.util.ArrayList; @SuppressWarnings({"rawtypes","unchecked"}) static void main(String[] args) { var list = Stream.of(new Foo(2, "foo"), new Foo(2, "bar")) .sorted().toList();
|
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
[repost with a link] The main issue with this kind of code is that the JIT does not see through the ClassValue. Tweaking a little bit your code, I get (It's a PITA that we have to use a raw type to workaround circularly defined parameter type)
R?mi |
1 similar comment
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
[repost with a link] The main issue with this kind of code is that the JIT does not see through the ClassValue. Tweaking a little bit your code, I get (It's a PITA that we have to use a raw type to workaround circularly defined parameter type)
R?mi |
Mailing list message from John Rose on core-libs-dev: On Jun 3, 2021, at 3:17 PM, forax at univ-mlv.fr<mailto:forax at univ-mlv.fr> wrote: ________________________________ interface ComparableRecord<T extends Record & ComparableRecord<T>> record Foo(int x, String y) implements ComparableRecord<Foo> { ? } http://cr.openjdk.java.net/~jrose/draft/ComparableRecord.java [repost with a link] The main issue with this kind of code is that the JIT does not see through the ClassValue. Wow, it?s almost as if we?ve discussed this already! ;-) Currently, the translation strategy for Records If ClassValue were performant, we could have Looking further, it would be nice to have methods Tweaking a little bit your code, I get (It's a PITA that we have to use a raw type to workaround circularly defined parameter type) I tried to DTRT and got into Inference Hell, surrounded Inspired by your more whole-hearted use of streams ? John |
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
yes, it's a specialization problem. interface ComparableRecord <please-always-reified-me T extends Record & ComparableRecord< T > > extends Comparable< T > { default int compareTo(T other) {
R?mi |
1 similar comment
Mailing list message from forax at univ-mlv.fr on core-libs-dev:
yes, it's a specialization problem. interface ComparableRecord <please-always-reified-me T extends Record & ComparableRecord< T > > extends Comparable< T > { default int compareTo(T other) {
R?mi |
/integrate |
@stuart-marks Since your change was applied there have been 112 commits pushed to the
Your commit was automatically rebased without conflicts. Pushed as commit cd0678f. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
I'm fixing this along with a couple intertwined issues.
Add Map.Entry::copyOf as an idempotent copy operation.
Clarify that AbstractMap.SimpleImmutableEntry is itself unmodifiable (not really immutable) but that subclasses can be modifiable.
Clarify some confusing, historical wording about Map.Entry instances being obtainable only via iteration of a Map's entry-set view. This was never really true, since anyone could implement the Map.Entry interface, and it certainly was not true since JDK 1.6 when SimpleEntry and SimpleImmutableEntry were added.
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.java.net/jdk pull/4295/head:pull/4295
$ git checkout pull/4295
Update a local copy of the PR:
$ git checkout pull/4295
$ git pull https://git.openjdk.java.net/jdk pull/4295/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 4295
View PR using the GUI difftool:
$ git pr show -t 4295
Using diff file
Download this PR as a diff file:
https://git.openjdk.java.net/jdk/pull/4295.diff