Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't remove the element in a mutable set if it is modified in Kotlin

Tags:

kotlin

I have an issue when using removeAll(), some objects can't be removed properly.

data class Dog(var name: String)

val dog1 = Dog(name = "dodo")
val dog2 = Dog(name = "mimi")

val set = mutableSetOf<Dog>()
set.add(dog1)
set.add(dog2)

dog1.name = "dodo2"

val beforeSize = set.size // 2

set.removeAll { true }

val afterSize = set.size  // why it is 1!?, I expect it should be 0

The removeAll didn't work as I expected. There is still one element in the mutable set. Any idea?

like image 714
Cody Avatar asked Apr 04 '18 08:04

Cody


1 Answers

Javadoc of Set:

Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set.

By writing

dog1.name = "dodo2"

you did exactly that, you changed the object in a way that affects equals comparisons. Specifically, by using the construct

set.removeAll { true }

you exercised a code path in LinkedHashSet that visits each element, tests the predicate on it, and then tries to remove it as if by calling set.remove(it). This will cause it to recalculate its hash code, now different from what it was when you inserted it into the set. LinkedHashSet will then look up the corresponding hash bucket and fail to find it there.

like image 113
Marko Topolnik Avatar answered Oct 23 '22 14:10

Marko Topolnik