I noticed strange behaviour with `ArrayDeque<E&...
# stdlib
s
I noticed strange behaviour with
ArrayDeque<E>
and its implementation of
MutableList<E>.removeAll(elements: Collection<E>)
, it doesn't work when
elements
are view created by
subList
. Method's invocation doesn't produce any kind of RuntimeException, but no elements are actually removed. example:
Copy code
val arrayDeque = ArrayDeque((1..10).toList())
val subList = arrayDeque.subList(arrayDeque.size - 3, arrayDeque.size)
arrayDeque.removeAll(subListł)
println(arrayDeque) // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
when passed new list object as an argument for example by calling
slice
, it all works fine:
Copy code
val arrayDeque = ArrayDeque((1..10).toList())
val subList = arrayDeque.slice(arrayDeque.size - 3..arrayDeque.lastIndex)
arrayDeque.removeAll(subList)
println(arrayDeque) // [1, 2, 3, 4, 5, 6, 7]
Using different kind of MutableList also works just fine:
Copy code
val mutableList = (1..10).toMutableList()
val subList = mutableList.subList(mutableList.size - 3, mutableList.size)
mutableList.removeAll(subList)
mutableList // [1, 2, 3, 4, 5, 6, 7]
Also, invoking
.subList(...).clear(...)
on ArrayDeque results in the same issue, no elements are being removed Should this be reported as a bug?
In the end I've created an issue for it just in case anyone wanted to follow: https://youtrack.jetbrains.com/issue/KT-55285
k
This is working as per the documentation of `subList`: "Structural changes in the base list make the behavior of the view undefined."
s
But the issue here is not with the behavior of the view, but with the behavior of base list, in my example I don't necessarily care about how the view is affected after
removeAll
call. As per documentation of `removeAll`: "Removes all of this collection's elements that are also contained in the specified collection"
Copy code
public override fun removeAll(elements: Collection<E>): Boolean = filterInPlace { !elements.contains(it) }
from ArrayDeque would also suggest logic boiling down to iterating through view elements and removing all elements from base that are also contained in view. Cannot see how
elements
being view should change its behavior
k
Since
subList
returns a view of the original list, and you are modifying the original list, the behaviour of the view is undefined. Since you are modifying the original list based on a view that is undefined, the result of the operation is therefore also undefined.
🙏 1
s
I expected
ArrayDeque
to act similarly to
ArrayList
as in provided example, but you're right that this expectation might have been incorrect. Will therefore avoid using views for any mutations of the original collections in the future, thanks!