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
Method put of JCollectionWrappers returns None if the old value is null #11894
Comments
This is a bit tricky, in that I'm not an expert, but the Java API is uniform in treating I like the size check trick, if size is cheap. I think it's necessarily true that some code somewhere relies on the current behavior. |
This is only true for the concrete concurrent implementations in Java. The non-concurrent ones can hold
It is. I am just a little worried that concurrent modifications (for example by the GC in WeakHashMap) between the TestsI ran some tests for most Scala- and most Java-maps: Full Table
def wrapped(underlying: ju.concurrent.ConcurrentMap[A, B]) = new ju.concurrent.ConcurrentMap[A, B] {
override def size(): Int = underlying.size()
...
override def putIfAbsent(key: A, value: B): B = underlying.putIfAbsent(key, value)
} More methods are affected:Assume val mJava = wrapped(asJava(new concurrent.TrieMap[A, B]()))
mJava.put(a1, null)
val m = asScala(mJava)
m.putIfAbsent(a1, b1) // does nothing
m.getOrElseUpdate(a1, b1) // does nothing
println(mJava.containsKey(a1)) // true
println(m.contains(a1)) // false, expected: true
println(mJava.get(a1)) // null
println(m.get(a1)) // None, expected: Some(null) So, why does |
I meant to say, for example, |
In JMapWrapperLike, treat null-values correctly: Return Some(null) instead of None, if the value is present, but null.
So |
Wow, I just unfurled the impressive table of operations. Feb 25 was just after my febrile period, so I don't know what I was thinking then. On So my conclusion is that a user wanting null sensitivity will have to do something laborious. (Inspect Some doc would help. The Javadoc says "this class behaves somewhat differently from other Map implementations." Is it worth doing Is it worth changing the Scala semantics to return I can use Edit: another idea is to provide And Edit: submitted the less eccentric patch. |
There was discussion on scala/scala#9344, now abandoned. I don't think we have consensus on whether the current behavior is wrong or not. (I lean, gently, towards the status quo unless someone appears and steps forward with a clear, strong case for the change. Perhaps there is one, there in the back-and-forth.) |
Java also has trouble keeping this straight. A current bug "TreeMap.computeIfAbsent Mishandles Existing Entries Whose Values Are null" |
Short example:
Explanation
mutable.WeakHashMap
is implemented by aJMapWrapper
and inherits itsput
method fromJMapWrapperLike
, which states as follows:If a key is not present,
put
shall returnNone
as it does, but if it is present, the documentation (inmutable.Map
) says that the result should be aSome
containing the previous value, soSome(null)
.In fact,
mutable.HashMap
behaves like this.The problem is, that the implementation relies only on the
put
method of the underlying Java-map, which returnsnull
in both cases: when the key is not present and when its associated value is null.Solution Idea
A straight-forward fix would be
But this requires two accesses to the underlying map (
contains
andput
both have to lookup the relevant entry) so the cost doubles. (Neglecting caching)To (nearly) keep the current performance, one could take something like:Notes
size
really safe here? (Or may this lead to conflicts with the GC inWeakHashMap
? Edit: It does!)s.c.c.JavaCollectionWrappers
.putIfAbsent
is also somehow affectedmutable.Map
sSome
's content not beingnull
when returned byput
?The text was updated successfully, but these errors were encountered: