You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
computeIfAbsent is annoying: The reason that almost everyone uses it is to insert a non-null value into the map if no value is yet present for that key. But very occasionally, people pass in a function that returns null, which is a perfectly valid thing to do according to the documentation and which is handled properly by implementations. But the natural result of that is that the return type of the method would @Nullable V, which is annoying for everyone else, requiring the kinds of suppressions and !!s that give people warnings blindness and give nullness checking a bad name.
Given that, a65745b (later commented upon in #32) annotated computeIfAbsent to require a function that returns plain V—and thus to have a return type of plain V[*]. This follows Kotlin's behavior (and following Kotlin's behavior may be important for some users for pragmatic reasons), and I had to migrate only one Kotlin caller (who was invoking the method on a Java Map subtype) to use compute instead (which required only a second function parameter and an associated if (existing != null) return existing).
I still feel reasonably good about that, if not completely good. We could talk again about whether to support nullable values.
(Yes, I think @PolyNull would be nice here, as in the Checker Framework, and one option would be to use @Nullable in the signature of computeIfAbsent but program special logic into checkers to give the method @PolyNull-like behavior, as they'll likely already want to do for methods like Optional.orElse.)
This issue is not about that. (Maybe I should preemptively open one now that is about that... :)) What this issue is about is whether to more aggressively use @NonNull. We could do so by making the V type in the function @NonNull and by making the return type @NonNull. This could theoretically maybe someday help someone who wants to use computeIfAbsent on a map with a nullable value type but still wants to get a non-null V out.
I'm actually filing this issue mostly to discuss a couple reasons not to do that:
As noted above, our current signature matches Kotlin's built-in treatment of the Map method.
An explicitly non-null type would close off escape hatches for getting a null through computeIfAbsent:
It might encourage tools to insert runtime null checks more aggressively.
It prevents you from casting your Map<Foo, Bar> to a Map<Foo, @Nullable Bar> and then being able to pass a null through without any problem.
(I also was mistakenly thinking that there was a separate opportunity to add @NonNull elsewhere in the signature. But I was thinking of cases like computeIfPresent, which receive a non-null "existing value" parameter, which obviously doesn't make sense for computeIfAbsent.)
[*] Observant readers may have noted that I made similar changes for compute and computeIfPresent and that merge was already in a similar boat. But I subsequently changed those methods to use @Nullable types after all (in #14 and #32).
The text was updated successfully, but these errors were encountered:
computeIfAbsent
is annoying: The reason that almost everyone uses it is to insert a non-null value into the map if no value is yet present for that key. But very occasionally, people pass in a function that returnsnull
, which is a perfectly valid thing to do according to the documentation and which is handled properly by implementations. But the natural result of that is that the return type of the method would@Nullable V
, which is annoying for everyone else, requiring the kinds of suppressions and!!
s that give people warnings blindness and give nullness checking a bad name.Given that, a65745b (later commented upon in #32) annotated
computeIfAbsent
to require a function that returns plainV
—and thus to have a return type of plainV
[*]. This follows Kotlin's behavior (and following Kotlin's behavior may be important for some users for pragmatic reasons), and I had to migrate only one Kotlin caller (who was invoking the method on a JavaMap
subtype) to usecompute
instead (which required only a second function parameter and an associatedif (existing != null) return existing
).I still feel reasonably good about that, if not completely good. We could talk again about whether to support nullable values.
(Yes, I think
@PolyNull
would be nice here, as in the Checker Framework, and one option would be to use@Nullable
in the signature ofcomputeIfAbsent
but program special logic into checkers to give the method@PolyNull
-like behavior, as they'll likely already want to do for methods likeOptional.orElse
.)This issue is not about that. (Maybe I should preemptively open one now that is about that... :)) What this issue is about is whether to more aggressively use
@NonNull
. We could do so by making theV
type in the function@NonNull
and by making the return type@NonNull
. This could theoretically maybe someday help someone who wants to usecomputeIfAbsent
on a map with a nullable value type but still wants to get a non-nullV
out.I'm actually filing this issue mostly to discuss a couple reasons not to do that:
Map
method.null
throughcomputeIfAbsent
:Map<Foo, Bar>
to aMap<Foo, @Nullable Bar>
and then being able to pass anull
through without any problem.(I also was mistakenly thinking that there was a separate opportunity to add
@NonNull
elsewhere in the signature. But I was thinking of cases likecomputeIf
Present
, which receive a non-null "existing value" parameter, which obviously doesn't make sense forcomputeIf
Absent
.)[*] Observant readers may have noted that I made similar changes for
compute
andcomputeIfPresent
and thatmerge
was already in a similar boat. But I subsequently changed those methods to use@Nullable
types after all (in #14 and #32).The text was updated successfully, but these errors were encountered: