-
Notifications
You must be signed in to change notification settings - Fork 26
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
Non-null projection of a type variable usage #86
Comments
I am currently thinking this concept may not apply to wildcards. The way to think about wildcards is perhaps instead #88. |
Trying to summarize where I think we stand, part 1: Projecting to non-null We don't think there is much need for this in practice:
But this is all distinct from other questions:
|
Trying to summarize where I think we stand, part 2: Projecting to unspecified nullness This is a bit harder to summarize. We suspect that users will want something kind of like this on occasion:
However, in the second case (and perhaps the first, too, if However, if they instantiate My model for this is that As in the previous post, though, we might or might not feel that we can give [*] To produce an effect much like |
(FWIW, |
I don't have a particularly strong opinion, but FWIW: I would see that as covered by the second paragraph of Type Arguments of Parameterized Types, which says to ignore the |
Agreed on the ignoring if the type parameter was bounded by non-null. I meant to say that that's not the only possible way of specifying
|
Ah, thanks, now I get it, and I'm not sure what else I could have thought the first sentence of your previous post meant :) While I've spoken against "unnecessarily" nullable bounds in the past (like on
I am maybe somewhat still vaguely against a nullable bound here, simply because I like the idea of encouraging users to always pick the "obvious" signature when annotating their own code (and especially writing stub files, since multiple users might write stubs for the same API, and it would be nice for them to agree). But I'm not that opposed. And it's not like we'd have to add a new feature to allow it. (This ends up not being that relevant, but out of curiosity, I looked at what percentage of callers of |
I tried to search Google's codebase for cases in which CF users needed I didn't find much, though I was searching for a very specific pattern, as discussed in this post, in which I also report the results. (Most of what my search turned up was various proxying/intercepting use cases, like retrying, rate limiting, and memoizing, in which the input object had to be non-null.) If anyone has ideas for patterns of "project to non-null" that I could look for, including other patterns of using |
[@wmdietlGC , since we recently spoke about nullable instantiations of |
RE: needing I could also imagine searching for methods that accept a [*] maybe starting with a search like |
(Possibly exception: arrays, for which you can't use wildcards. But arrays are trouble all around.) |
I can believe that examples like
@wmdietlGC seems to feel that things like |
You might be looking for this @wmdietlGC post. I should note that Guava implementation code did contain one usage of I will see how I can search for users of |
Oops, I did already look into that, but I put the information into a comment thread and then resolved it.... I moved it into the doc body, but it's short enough to quote here:
|
Sorry, I take that back. While
Still, the workaround is straightforward. |
One use case for projecting to non-null that is still hypothetical but looks more realistic (if far away): a Optional<@NonNull V> getOptional(@Nullable Object key); See JDK-8204662 and JDK-8232647. The former notes that the JDK owners may consider this once value types exist. The alternative to supporting such a projection is:
(Or maybe someday we'll have a way to say that the method can be called only on a (My personal position is still to avoid supporting projection to non-null, but this is at least a small argument to the contrary.) |
Hmm we might be approaching critical mass here. Another somewhat similar example that would benefit from projections was a |
I do think these are all important possibilities to have an eye on. At the same time, I think it's worth remembering that they are all currently hypothetical. (Additionally, Valhalla in particular is still far off, and the subsequent library improvements could be further still, and both could happen in non-LTS releases and thus take even longer to get to users.) It's still nice to support what we can. I claim only that the use cases are small enough that they're not decisive on their own. We get to weigh them against the costs (which I grant are not enormous but which I think are non-obvious), similar to how we weigh the (larger) costs and benefits of including (All that said, it does seem fairly likely to me that, if we include |
To me, the fact that these are examples from APIs that Java developers use
~ every day does suggest significant importance. They may be hypothetical,
but on the other hand, if we don't have ideas on how to design them to
avoid projections, that still suggests to me that we may be missing
functionality that could be important more generally.
`@PolyNull` to me is a bit different only because it seems that it can be
added "later" with relative ease, and the question there is more how best
to do it (`@PolyNull` vs `@Contract`). There are also relatively clear
ways of avoiding the need for `@PolyNull` in new APIs (e.g., `orNullI()` :)
).
Just to repeat something I mentioned before, *if* we define
`Optional<Anything>` to implicitly project the type argument to `@NonNull`
because that's `Optional`'s type parameter bound, then we still don't need
explicit projections to handle `Optional`-related examples.
|
I believe @cpovirk has been collecting up use cases for this. (If we decide to have this then it will need an annotation; and if that annotation wants to be |
3 known APIs from Guava, all around "A type parameter that wants nothing to do with nullness" (#78), either in the form of [edit: And maybe someday we'll also want this for a hypothetical
|
Is Today: class Optional<T extends Object>
class FluentIterable<E extends @Nullable Object> {
@SuppressWarnings("nullness") // it's broken, but we seem to have no choice
Optional<E> first() { ... }
} Alternative? Optional<@NonNull E> first() {
return Optional.of(...); // if it wouldn't satisfy the projected type it will throw anyway
} [cpovirk edit: Similarly, |
Yes, thanks. (And to be clear, there are multiple similar methods on that class.) I had gotten too discouraged and distracted about And as noted in that same comment, tools could conceivably be made smart enough to identify bad usages of the methods. (Hmm, maybe they could be made to identify the need to project to non-null automatically even without the annotation?) A nice bonus of being able to declare the return type correctly is that we would no longer have to suppress warnings at the method level, only at the actual unsafe call. (Granted, if we're able to design sophisticated warning suppression and get it adopted widely, then the method-level suppression could perhaps be written in a way less likely to mask other errors.) |
This sounds dodgy. If yes on this issue then they should project the normal way and remove the warning suppression. If no on it, the warning and need to suppress are justified. And then even at the call site (still referencing your linked comment, here) I would have wanted to get a warning any time any expression at any granularity has a bogus static type. |
minor note: I've been referring to |
Using the
Separately: what is the very best we can do for these use cases if we don't have non-null projection? It would of course be very strange for people to actually get an |
(question for @cpovirk there) |
I've subsequently said a couple things on #158, and I'm not sure if they were the right direction to take the conversation or the right thing to say them on. But there's a fairly direct question here that I think I can belatedly answer. What we have now is probably the best option:
The result of that is that it's possible to end up with what our rules would consider to be an But "the So I'd anticipate issues only if someone is trying to implement a method whose return type is Until we can convince ourselves that a new rule would be important to users, I'd lean against having one: While the handling of (But assuming that we do #230, we'll very likely do the topic of this issue, too, in which case we don't have to worry much about |
Working decision (as discussed in last meeting): yes, we will have |
For background, see jspecify/jspecify#86 (comment) RELNOTES=n/a PiperOrigin-RevId: 517437923
For background, see jspecify/jspecify#86 (comment) RELNOTES=n/a PiperOrigin-RevId: 519736884
…nonnull ...>`. (prompted by the mention of `Class` types in cl/519736884) This lets us express that they can contain null values. See discussion in jspecify/jspecify#86 (comment) RELNOTES=n/a PiperOrigin-RevId: 526184065
I should admit here that I have since learned of a JDK method that does use non-null projection in the way that people normally think of it (i.e., not just for |
Hmm. They've continued to prove rare? Was there an issue where we were considering whether |
Up until the
We may of course still be missing others, but I think we'd be hearing from our Checker Framework users if any of them were of great importance. |
If anything, I'm inclined to view the rarity as more reason not to reconsider: Apparently users won't have to reach for In fairness, I do expect users to hit this more than I'm suggesting here: If you're writing Kotlin, or if you're writing Java using the Checker Framework's "default defaults," then you'll get in trouble if you write a " So I do expect users to be confused sometimes. Hopefully we can find ways to manage that, but "automatically conform to bounds" is not at the top of my list. |
Current decision: Yes, Argument for changing: It would be simpler not to support nullability projections. However, no strong case was made for changing the decision. Timing: This must be decided before version 1.0 of the jar. Proposal for 1.0: Finalize the current decision. If you agree, please add a thumbs-up emoji (👍) to this comment. If you disagree, please add a thumbs-down emoji (👎) to this comment and briefly explain your disagreement. Please only add a thumbs-down if you feel you can make a strong case why this decision will be materially worse for users or tool providers than an alternative. Results: This proposal received six 👍s and no other votes. It is finalized. I'll edit the title to reflect that. |
Decision: |
We've agreed to support the "nullable projection of a type variable"; that is, for a type variable
T
, the ability to denote the type representing "T union null"? This would presumably be written@Nullable T
. (Of course, we get that for free with the way we've conceptualized what "Nullable" means.)Should we support the "non-null projection of a type variable"; denoting the type "T minus null"? On this we seem to have less agreement, so let's look at use cases.
The text was updated successfully, but these errors were encountered: