Skip to content
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

Improve annotations on some java.util.concurrent collections. #9

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

cpovirk
Copy link
Contributor

@cpovirk cpovirk commented Apr 28, 2022

No description provided.

@@ -263,7 +265,7 @@ public int indexOf(@Nullable Object o) {
* {@code -1} if the element is not found.
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public int indexOf(E e, int index) {
public int indexOf(@Nullable E e, int index) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why is this change desirable (same for lastIndexOf below)? If the collection only accepts non-null elements, why allow checking with a null value? It won't throw an NPE, but it will always be false.
The indexOf variant that takes an Object needs to take an @Nullable Object parameter to allow both instantiations of the collection, but that doesn't apply here.

If you think they are indeed correct, having a @CFComment would be useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Part of my goal here is consistency, too: contains already has a @Nullable parameter. So let's make them all @Nullable or all not @Nullable.

The broader question is still a good one. As in our retainAll discussion, I've been operating under the principle of "accept the most general type that can't lead to NPE," but of course we're well aware that the principles here are controversial :) (That's not necessarily even my personal favored principle.)

I probably should have sent the poll and peek changes (which probably actually affect users) separately from the more complicated changes. It would be nice to get those in. But for the changes we've been discussing, I don't think we're affected much by what we decide to do, so we can continue discussing or just drop them, as you prefer.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contains takes an Object parameter, so that discussion should go along with the other Object vs. @Nullable Object methods.
For methods that take the type parameter, I don't see a benefit in allowing null. I agree that it wouldn't cause an NPE, but it would just allow calls that will return false. Is there a particular pattern where this would be much more convenient?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, thanks, I had forgotten about the distinction of Object vs. E. I am a bit surprised that they use E here, given the precedent of List.indexOf, but of course there are good arguments for not permitting calls that will always return false (compare https://errorprone.info/bugpattern/CollectionIncompatibleType). And if their goal is to use E to forbid such calls, then it's natural to extend that argument to keeping the type as E instead of @Nullable E.

I might still lean toward @Nullable E if we were writing The Official JSpecify Stubs: The theory would be that, if we didn't, tools could choose to insert runtime null checks for code that calls indexOf on a CopyOnWriteArrayList<@NonNull String>. But my recollection is that the only tool in common use that inserts such checks, Kotlin, does not insert checks in that particular case.

But for Checker Framework users (and for all non-hypothetical use cases), I'm not aware of examples in which @Nullable would improve anyone's life.

@@ -579,7 +581,7 @@ public E peekLast() {
}
}

public boolean removeFirstOccurrence(Object o) {
public boolean removeFirstOccurrence(@Nullable Object o) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this change (and the ones to removeLastOccurrence and remove below) go into collection-object-parameters-may-be-null.astub instead?
I see some entries there, e.g. for Deque.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My impression has been that these files haven't quite reached a consistent state.

LinkedBlockingDeque already has @Nullable on its contains method. That method's docs don't mention null explicitly, but they do say...

this deque contains at least one element e such that o.equals(e)

...which at best implies that null is an acceptable input.

The methods I'm annotating in this PR are similar. So I think it would be defensible to remove the annotation on contains, rather than add the ones in this PR. (And as you say, we could update collection-object-parameters-may-be-null.astub to have the annotations for all the methods.)

I can do that, but I'll wait for confirmation just in case. But probably nothing I've said above will come as a surprise :)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It unfortunately looks like there is some inconsistency here about which methods take @Nullable Object here or in collection-object-parameters-may-be-null.astub and I don't see a pattern.
As most of the changes in this PR are related to this, I think it would be great to merge the other changes and separately clean these methods.

Copy link
Member

@wmdietl wmdietl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would suggest we remove the @Nullable E parameter and @Nullable Object parameter changes and merge the rest. Making the other signatures consistent is worth separate PRs. What do you think?

@@ -579,7 +581,7 @@ public E peekLast() {
}
}

public boolean removeFirstOccurrence(Object o) {
public boolean removeFirstOccurrence(@Nullable Object o) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It unfortunately looks like there is some inconsistency here about which methods take @Nullable Object here or in collection-object-parameters-may-be-null.astub and I don't see a pattern.
As most of the changes in this PR are related to this, I think it would be great to merge the other changes and separately clean these methods.

@@ -263,7 +265,7 @@ public int indexOf(@Nullable Object o) {
* {@code -1} if the element is not found.
* @throws IndexOutOfBoundsException if the specified index is negative
*/
public int indexOf(E e, int index) {
public int indexOf(@Nullable E e, int index) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

contains takes an Object parameter, so that discussion should go along with the other Object vs. @Nullable Object methods.
For methods that take the type parameter, I don't see a benefit in allowing null. I agree that it wouldn't cause an NPE, but it would just allow calls that will return false. Is there a particular pattern where this would be much more convenient?

cpovirk added a commit to cpovirk/jdk that referenced this pull request May 4, 2022
Split off from eisop#9, which also contains
some changes whose usefulness is unclear.
@cpovirk
Copy link
Contributor Author

cpovirk commented May 4, 2022

I would suggest we remove the @Nullable E parameter and @Nullable Object parameter changes and merge the rest. Making the other signatures consistent is worth separate PRs. What do you think?

I created #16 with the changes that I think are uncontroversial. Once we get what we can merged there, I can merge that into this PR's branch, and we can figure out if/when we want to resume talking annotation philosophy :)

@wmdietl
Copy link
Member

wmdietl commented May 4, 2022

I created #16 with the changes that I think are uncontroversial. Once we get what we can merged there, I can merge that into this PR's branch, and we can figure out if/when we want to resume talking annotation philosophy :)

Thanks! I've merged #16 and pulled master back in here. As noted there, the removeAll/retainAll changes we discussed https://github.com/eisop/jdk/pull/9/files#r862552217 could also be merged and further minimize the leftovers from this PR.

@cpovirk
Copy link
Contributor Author

cpovirk commented May 5, 2022

Thanks. I might let this (including removeAll/retainAll) drop until I feel like I can spend some more time on forming some opinions, just given that I have some other things I've been neglecting. Thanks for looking at the flurry of PRs. Hopefully I'll end up with another idea or two soon :)

@wmdietl
Copy link
Member

wmdietl commented May 5, 2022

Thanks. I might let this (including removeAll/retainAll) drop until I feel like I can spend some more time on forming some opinions, just given that I have some other things I've been neglecting. Thanks for looking at the flurry of PRs. Hopefully I'll end up with another idea or two soon :)

Sounds good. Thanks for all the PRs and discussion!

cpovirk added a commit to cpovirk/jdk that referenced this pull request Sep 7, 2023
Ao-senXiong pushed a commit to Ao-senXiong/jdk that referenced this pull request Apr 21, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants