Kotlin / kotlinx.collections.immutable

Immutable persistent collections for Kotlin
Apache License 2.0
1.12k stars 56 forks source link

java.util.ConcurrentModificationException in PersistentMap.mutate {} #146

Open AbelToy opened 1 year ago

AbelToy commented 1 year ago

Using put multiple times in PersistentMap.mutate block results in java.util.ConcurrentModificationException.

Can be reproduced in 0.3.5 with the following code:

val initialData = Array(100) { i -> i to i * 2 }
val map = persistentMapOf(*initialData)

map.mutate {
    it.forEach { (key, value) -> it[key] = value }
}
ilya-g commented 1 year ago

That is rather expected: a mutable map cannot be mutated while it is iterated.

AbelToy commented 1 year ago

replaceAll causes the same issue…

fitermay commented 1 year ago

The parameter of the mutate lambda is a mutable map, not the persistent map itself. The ‘it’ iterated by the forEach loop is the mutator, not the persistent map. So what you intend to do should work if you write ‘map.forEach’ instead of ‘it.forEach’

AbelToy commented 1 year ago

@fitermay I can confirm map.forEach works.

However, I am stumped as to why it.replaceAll causes a ConcurrentModificationException

JajaComp commented 7 months ago
            val items = listOf(1, 2, 3, 4, 5).toPersistentList()
            val changeItems = items.mutate {
                it.forEachIndexed { index, item ->
                    it[index] = item * 10
                }
            }
            println(changeItems)

Cause error:

Caused by: java.util.ConcurrentModificationException
                                                    at kotlinx.collections.immutable.implementations.immutableList.PersistentVectorMutableIterator.checkForComodification(PersistentVectorMutableIterator.kt:127)
14:53:20.035 AndroidRuntime                  E      at kotlinx.collections.immutable.implementations.immutableList.PersistentVectorMutableIterator.next(PersistentVectorMutableIterator.kt:58)
ajrouvoet commented 2 weeks ago

I'm also bitten by this, using replaceAll on the mutator. It is not clear to me at all that this is unintended use of the mutator, if that is the case. Can you clarify if this is a user error or a bug?