Open xenoterracide opened 2 months ago
P.S. the docs say that getFirst is fictitious which is no longer true as of java 21.
Ha that is a good find!
is E get(int index); automatically @Nullable here?
No. It is whatever the declaration is. Let us assume we are in code bases with NullMarked.
List<String> list = ...;
var e = list.get(0); // e is nonnull here.
and
List<@Nullable String> list = ...;
var e = list.get(0); // e is nullable here.
Again assuming a @NullMarked
code base that the interface List is in:
public interface List<E> {
Means E is always nonnull. I guess you could think of it as List<E extends @NonNull Object>
.
There are some tools that allow flexibility on this but essentially parameter definitions are nonnull unless marked as nullable.
public class ImmutableList<@Nullable E> {
I assume the above implements our nonnull List of List<E>
and not the extends nullable of the actual java.util.List right ?
The tools currently will allow it but I think in JSpecify in spirit should be an error.
public interface List<E extends @Nullable Object>
so why do this?
Also, what happens if you have var list
instead of List<String> list
, these days I rarely need to write the latter.
I assume the above implements our nonnull List of List
and not the extends nullable of the actual java.util.List right ?
yes, although, that is a good example of maybe why the examples shouldn't be List
? it's not very common to be writing a List
interface.
public interface List<E extends @Nullable Object>
...lets users write both List<[@NonNull] String>
and List<@Nullable String>
. That way, users who don't want to put nulls into their lists don't have to deal with the nullable return from methods like get
, but users who do want to put nulls in can still do so.
That's in contrast to...
public interface List<E [extends @NonNull Object]>
...which would allow only "one kind" of List
. (That would force us to choose between "No lists contain nulls" (which is limiting) and "All lists may contain nulls" (which is inconvenient).)
I have a doc that has a list of types to demonstrate when various combination of nullnesses may be useful for generic types. Here's a snippet:
@NullMarked
interface Factory<T extends @NonNull Object> {
T newInstance();
}
@NullMarked
interface BlockingQueue<E extends @NonNull Object> {
@Nullable E peek();
}
@NullMarked
interface Supplier<T extends @Nullable Object> {
T get();
}
@NullMarked
interface NavigableSet<E extends @Nullable Object> {
@Nullable E pollFirst();
}
public class ImmutableList<@Nullable E> {
As noted, we define that as an inapplicable location for @Nullable
. If you want to say that ImmutableList
is a list that always permits null elements, then you'd write:
public class ImmutableList<E> implements List<@Nullable E>
Guava actually has one weird type like that, ArrayTable
, and a couple less weird types like that, Equivalence
and Converter
. (Hmm, no, wait, we didn't actually annotate Converter
to have a supertype of Function<@Nullable A, @Nullable B>
, only Function<A, B>
. But the other two examples stand.)
Also, what happens if you have
var list
instead ofList<String> list
, these days I rarely need to write the latter.
The type would be inferred from the right-hand side of the assignment (e.g., new ArrayList<String>()
or new ArrayList<@Nullable String>()
). If you use the diamond operator on the right-hand side, then, well, we have thus far left type inference up to tools :( I'd kind of expect them to infer List<@Nullable Object>
, similar to how javac (I think) infers List<Object>
in the same situation, but I haven't thought about this much.
(And yes, the real thing we need to do here is to improve our docs.)
Sort of off topic but I guess I missed that @NonNull
was added (hence my hesitation to actually use the annotation for example).
Was it always available? I swear its not in JSpecify 0.3.
EDIT I guess I missed it: https://github.com/jspecify/jspecify/releases
@cpovirk
Now that I'm looking at the Javadoc of NonNull a note should probably be added either below or addition to:
Where it is not applicable
@NonNull
is inapplicable in all the same locations as Nullable.
That you should not combine the @Nullable
and @NonNull
annotations on the exact same spot.
I'm not even sure what checker does in that case but I assume its an error. I'll check later (pun intended).
@NonNull
is inapplicable in all the same locations as Nullable.
EDIT never mind. I'm slow today I see it now on Nullable javadoc:
If both
@Nullable
and@NonNull
appear on the same type usage, neither one is recognized.
Well, I was about to boldly claim that "@Nullable @NonNull
means nothing" is not consequential enough to be among the first 400 words that I would want people to read about @NonNull
. (We do expect to have to provide lots of docs beyond the Javadoc, so there's a balancing act for what to include there.) I guess that claim doesn't look so good now that you've determined that we already say it :) (But maybe it's reasonable to include when we get 1k words to talk about @Nullable
!)
Looking at the first example
is
E get(int index);
automatically@Nullable
here?what if
List
were defined asand then
would
E get(
onImmutableList
automatically be nullable?P.S. the docs say that
getFirst
is fictitious which is no longer true as of java 21.