Reputation: 128
Why this code can be compiled and executed without erros?
val map = HashMap<Int, Long>()
val key :Int? = null
map.remove(key)
In MutableMap remove declared as accepting only non nullable key, so it shouldn't even compile. Is it a Kotlin type inference bug or am I missing something?
public fun remove(key: K): V?
Upvotes: 2
Views: 524
Reputation: 2492
In this case, map.remove(key)
doesn't not calls
public fun remove(key: K): V?
It calls an extension remove
function:
public inline fun <@OnlyInputTypes K, V> MutableMap<out K, V>.remove(key: K): V? =
@Suppress("UNCHECKED_CAST") (this as MutableMap<K, V>).remove(key)
This function documentation says that it allows to overcome type-safety restriction of remove
that requires to pass a key of type K
.
It allows overcoming type-safety restriction because the key of the entry you are removing does not have to be the same type as the object that you pass into remove(key)
; the specification of the method only requires that they be equal. This follows from how the equals()
method takes in an Any
as a parameter, not just the same type as the object.
Although it may be commonly true that many classes have equals()
defined so that its objects can only be equal to objects of its own class, there are many places where this is not the case. For example, the specification for List.equals()
says that two List
objects are equal if they are both List
s and have the same contents, even if they are different implementations of List
. So, for example, according to the specification of the method, it is possible to have a MutableMap<ArrayList<Something>, Something>
and call remove(key)
with a LinkedList
as an argument, and it should retrieve the key which is a list with the same contents. This would not be possible if this extension remove(key)
didn't exist.[1]
Upvotes: 2
Reputation: 75629
Your code is perfectly fine as remove()
allows nullable arguments - your map contents definition got nothing to it. When remove()
is invoked, it would try to find matching requested key in the map and as it's not there (it's completely irrelevant why it's not there - it's valid case for key to be not present) nothing will happen. Where compiler will complain is on any attempt to put such key into your map. Then map definition kicks in and since it's known that nullable keys not allowed, such code won't even compile as this is clearly buggy code.
Upvotes: 4
Reputation: 128
Eventually asking this question helped to find another question with explanation. In short, what actually happens is call of the extension function which have it's own type inference.
Upvotes: 0
Reputation: 18568
Kotlin could warn or refuse to compile (would be good), but it doesn't (for now).
The reason for it being not as bad as it looks from a first glance is that you cannot put
an Int?
into a MutableMap<Int, Long>
because
val map = HashMap<Int, Long>()
val key :Int? = null
map.put(key, 1) // <--- WON'T COMPILE [Type mismatch: inferred type was Int? but Int was expected]
map.remove(key)
Nevertheless, I think you are right by wondering about that method being compiled.
Upvotes: 1