Why is `Map.getOrElseNullable()` not public API? ...
# stdlib
m
Why is
Map.getOrElseNullable()
not public API? I’ve just now noticed that
.getOrElse()
doesn’t work as documented for
null
values.
Returns the value for the given key, or the result of the
defaultValue
function if there was no entry for the given key.
1
m
get(key) ?: if (containsKey(key)) null else defaultValue
may not work correctly with concurrent collections. But the current implementation is totally wrong and must have
V : Any
type parameter bound.
m
V : Any
would break some code that wants to return
V?
in
defaultValue
, for example:
map.getOrElse(key) { cache[key] }
Changing the return type of
defaultValue
to
V?
also won’t work as it’s always nullable then. I don’t see the issue with concurrent collections 🤔
m
The issue with concurrent collections is that
get
and
containsKey
could return inconsistent values. get() -> null other thread: put containsKey() -> true got null
there could be other type parameter
: V
for default and return value
m
there could be other type parameter
: V
for default and return value
I don’t think Kotlin can model that. You’d need
V
to be s subtype of
R
and also a subtype of
Any
.
get() -> null
other thread: put
containsKey() -> true
got null
So the only downside is that it would return the default value in a case where some other thread has added a
null
value in the meantime? I still don’t see how that is an issue.
getOrElse()
won’t fare much better. By the time the function has returned another thread may already have added/replaced the value due to lack of proper synchronization.
m
added a
null
value in the meantime
Any value.
m
The implementation only checks
containsKey if get() returned null. So in all
other cases it behaves like the normal
getOrElse
. Woah Slack's message formatting became really annoying recently.
m
And
get()
returns
null
when there's no such mapping. map = {} map.get(key) -> null map = {key=value} map.containsKey(key) -> true
m
getOrElseNullable
doesn't call
containsKey
unless
get
has returned
null
, so how can that lead to a race condition that would be different from a simple
get
in
getOrElse
?
m
Because your example is the special
null
case, yet you've said that it applies for all values, which isn't the case. And even if there is a race condition like that - I don't see how that is a problem at all since having that
get
and
containsKey
together in one atomic operation doesn't bring any benefit, since the caller of
getOrElseNullable
AND
getOrElse
still has race conditions with the map unless there is additional synchronization. It would be totally different for
getOrPut
as that one definitely needs to be atomic since it both reads and writes.
Ah, JB says there are simply not enough use cases. Time to file an issue then :) https://kotlinlang.slack.com/archives/C0B8Q383C/p1469388323000041