Skip to content
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

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

Open
AbelToy opened this issue Jun 2, 2023 · 7 comments
Open

Comments

@AbelToy
Copy link

AbelToy commented Jun 2, 2023

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
Copy link
Member

ilya-g commented Jun 2, 2023

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

@AbelToy
Copy link
Author

AbelToy commented Jun 2, 2023

replaceAll causes the same issue…

@fitermay
Copy link

fitermay commented Jun 3, 2023

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
Copy link
Author

AbelToy commented Jun 5, 2023

@fitermay I can confirm map.forEach works.

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

@JajaComp
Copy link

            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
Copy link

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?

@qurbonzoda
Copy link
Contributor

Please note that the mutable version passed into mutate {} wraps the same internal data structure as the immutable version. The mutable version copies parts of the data structure only on write. This makes structural change to the collection and invalidates active iterations. A more detailed exception message might help a bit. However, this unintuitive difference in behavior compared to stdlib collections requires a better solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants