-
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
Addressing cases like the AtomicReference zero-param constructor #145
Comments
This could hypothetically be nice for Guava's [edit: a little more on this] |
I'm gonna treat this issue as being about The Interesting Case Of # 3 seems worth trying for. The fact it at least stops you from actually setting a nullable reference is useful: then if an unexpected null does happen, it's easier to conclude that the setting code probably never ran, instead of wondering whether maybe that expression was itself unexpectedly null. If our hypothetical API owner agreed with that, then ideally they could proceed to make a design choice between options like:
# 3 leads to an interesting question: suppose the user A breaks the sequencing contract (for example because they don't have tools that know how to enforce it!), and user B uses the class correctly. The read methods can be annotated sensibly for user A (nullable) or user B (non-nullable), but we have to choose. EDIT: Call those options 3A and 3B. The difference between 3B and 2 is that 2 is just a lie, but 3B informs the user of what bounds they need to stay within, and tells the truth about what happens as they long as they do. One viewpoint toward 3A vs. 3B would be that 3B can only be justified if the sequencing contract is itself expressible through JSpecify. That maintains certain guarantees that tools would all be able to make. Personally, I favor 3B in either case. I think there are always a long tail of bad actions you can take that will break an object's state such that it doesn't conform to its contract. You can change a Guava ImmutableList through reflection, etc. |
FWIW another example for this is |
3B seems to kind of put AtomicReference itself into the same category as "fields" and "array components". All 3 have this initialization problem. |
So my proposal is that we use |
Came across this again; wrote up https://github.com/jspecify/jspecify/wiki/nullness-borderline-cases#the-atomicreference-case |
@wmdietlGC and I were talking about
AtomicReference
. We see ~3 ways to annotate it:All APIs operate on
@Nullable T
. (Then, for the declaration ofT
, we employ whatever pattern we prefer for parameters that want nothing to do with nullness.)All APIs operate on plain
T
.T
is declared to be definitely nullable. "Definitely nullable" is a feature that JSpecify may not support, at least initially, so this option would require additional support from tools.All APIs operate on plain
T
.T
is declared to permit both nullable and non-nullable type arguments.The problem with (3) is the no-arg
AtomicReference
constructor. It creates an instance whose value is null, even ifT
is a non-nullable type:So we might end up going with (1) for now. But (1) is annoying because it provides no way for JSpecify to know that
get()
returns a non-nullable value -- even if the user passed a non-null value to the constructor and never set the value to null.So we might like (3). That could take the form of:
new AtomicReference<>(null)
if that's what they want)(This problem does not exist with static factory methods, since we already provide a way to set bounds there.)
A "
@DoNotCall
" annotation is something that we could do someday (and something we've found useful in Error Prone), so maybe this is just our first issue to request that. Or maybe there's something nullness-specific here that we'd want to do.The text was updated successfully, but these errors were encountered: