kotlin icon indicating copy to clipboard operation
kotlin copied to clipboard

[JVM] Change ConcurrentMap.getOrPut from implicit Any! to Any

Open rgmz opened this issue 2 years ago • 2 comments

On the Kotlin Slack, @SecretX pointed out that ConcurrentMap.getOrPut allows null as the default value, which can cause a runtime error:

Why does Kotlin compiler let's this trap compile? I introduced an error in production today on my company because of this, I thought the compiler or the IDE would catch something like this, but apparently not.

ConcurrentHashMap<Int, String>().getOrPut(1) { null } // compiles just fine, but it'll throw in runtime
mutableMapOf<Int, String>().getOrPut(1) { null } // compiler error: Null can not be a value of a non-null type String

This is because with ConcurrentMap<K, V>.getOrPut the V is implicitly Any!, whereas with MutableMap<K, V>.getOrPut it's Any. Admittedly, this is a bit of a naive fix and will likely require some additional changes for cases where you actually want V: Any? (I have to check if that's legal).

rgmz avatar Dec 24 '21 18:12 rgmz

Currently, you can use null as a key as well, I think you might have to make K : Any too.

ConcurrentHashMap<Int, String>().getOrPut(null) { null } // compiles just fine, too

SecretX33 avatar Dec 24 '21 18:12 SecretX33

ConcurrentMap does not restrict keys and values to non-null values so with your change means it no longer works for those cases which I assume is a no go for the kotlin team. Remember that null support of maps is something the sub type gets to decide.

I think you have better luck getting an additional function included:

public inline fun <K : Any, V : Any> ConcurrentHashMap<K, V>.getOrPut(key: K, defaultValue: () -> V): V = ...

Citing the docs for ConcurrentHashMap:

 * <p>Like {@link Hashtable} but unlike {@link HashMap}, this class
 * does <em>not</em> allow {@code null} to be used as a key or value.

spand avatar Jan 03 '22 12:01 spand