Szymon Jeziorski
12/29/2023, 9:07 AMlist: List<T>
you can call list.removeFirst()
, or list.removeLast()
just as if you were calling MutableList<T>.removeFirst()
, or MutableList<T>.removeLast()
extensions. Similarly, addFirst/Last
methods are also visible
To me this sounds problematic for 2 main reasons:
• one might confuse the type being worked on - you wouldn't normally see mutating methods in autocomplete for objects exposed via read-only interfaces, so I can imagine someone mutating a collection by accident (especially by confusing with a well-known removeFirst/Last extension with the same name as the new interface's methods)
• just as in Java's world, the result of the operation depends on the underlying implementation, meaning you have to watch out for UnsupportedOperationException
againLaxystem
12/31/2023, 2:11 PMkotlin.MutableCollection
compiles to java.util.Collection
.
kotlin.Collection
and kotlinx.collections.immutable
are their own, standalone classes, that do not have equivalents in the JDK.
When using Kotlin, make sure not to accidentally import java.util
classes, as Kotlin's are automatically imported.Szymon Jeziorski
01/01/2024, 7:06 PMkotlin.collections.Collection
types are also types of java.util.Collection
, otherwise you wouldn't be able to use Java's Collections API on it, which of course you can.
fun main() {
val collection = PureKotlinCollection<Int>()
println(collection is java.util.Collection<*>) // always returns true
}
class PureKotlinCollection<E> : kotlin.collections.Collection<E> {
override val size: Int get() = TODO("Not yet implemented")
override fun isEmpty(): Boolean = TODO("Not yet implemented")
override fun iterator(): Iterator<E> = TODO("Not yet implemented")
override fun containsAll(elements: Collection<E>): Boolean = TODO("Not yet implemented")
override fun contains(element: E): Boolean = TODO("Not yet implemented")
}
From what I understand, distinguishing between Collection and MutableCollection allows compiler to prioritize Kotlin's interfaces over Java ones, and that's why having kotlin.collections.List
you cannot call add
method, because it is moved to seperate kotlin.collections.MutableList
interface.
Now, as I mentioned, the problem is, that every kotlin.collections.List
is also java.util.List
, therefore it is also SequencedCollection
in JDK 21.
Kotlin does not yet have dedicated interfaces as kotlin.collections.SequencedCollection
and kotlin.collections.MutableSequencedCollection
to allow the compiler prioritizing them and as a result affect original methods visibility. Because of that, you can call all the SequencedCollection
methods on any kotlin.collections.List
as presented on the snippet below
fun main() {
val listReadOnlyUnderneath: kotlin.collections.List<Int> = listOf(1, 2, 3)
val listMutableUnderneath: kotlin.collections.List<Int> = List(3) { it + 1 }
println(runCatching { listReadOnlyUnderneath.removeLast() }) // Failure(java.lang.UnsupportedOperationException)
println(runCatching { listMutableUnderneath.removeLast() }) // Success(3)
println(listReadOnlyUnderneath) // [1, 2, 3]
println(listMutableUnderneath) // [1, 2], list mutated
}
Laxystem
01/01/2024, 8:31 PMkotlin.collections.List
isn't always a java.util.List
. It can be a kotlinx.collections.immutable.ImmutableList
Laxystem
01/01/2024, 8:32 PMkotlin.collections.MutableList
is equivalent to java.util.List.
Laxystem
01/01/2024, 8:32 PMLaxystem
01/01/2024, 8:36 PMjava.util.List is kotlin.collections.List // true
java.util.List is kotlin.collections.MutableList // true
kotlin.collections.List is java.util.List // depends
kotlin.collections.MutableList is java.util.List // true
Szymon Jeziorski
01/01/2024, 8:42 PMkotlin.collections.collection
, where is java.util.Collection<*>
check returned true,
but here's example of kotlinx.collections.immutable.ImmutableList
to double prove myself. Please run it yourself if you don't believe me.
val immutableList = kotlinx.collections.immutable.persistentListOf(1, 2, 3)
println(immutableList is java.util.List<*>) // true
denis.zharkov
01/02/2024, 9:58 AM