Kotlin / kotlinx.collections.immutable

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

Lists and Sets should provide an implementation for `plusElement` #141

Open SebastianAigner opened 1 year ago

SebastianAigner commented 1 year ago

Adding elements to lists of lists unfortunately comes with long-standing resolution issues for the operator functions: https://youtrack.jetbrains.com/issue/KT-9992

That means the following code works:

var a = persistentListOf<Int>()
a += 1

but this code doesn't:

var b = persistentListOf<PersistentList<Int>>()
b += persistentListOf(1)

From the linked issue, via Roman Elizarov:

It looks that the root of the problem is that + is overloaded to mean both plusElement and plus (set union/list concatenation). Until it is addressed, everything else is just workaround.

The workaround in the standard library collections is using the plusElement function. However, no implementation for this function exists for persistent lists, so the implementation returning List<T> is chosen:

image

This means the APIs between regular read-only lists and persistent lists are quite divergent when it comes to adding elements to collections of collections:

val a = measureTimedValue {
    var list = listOf(0)
    var llist = listOf<List<Int>>()
    repeat(25000) {
        list = list.plusElement(it)
        llist = llist.plusElement(listOf(1,2,3))
    }
    llist
}

val b = measureTimedValue {
    var list= persistentListOf(0)
    var llist = persistentListOf<PersistentList<Int>>()
    repeat(25000) {
        list = list.plus(it)
        llist = llist.add(list)
    }
    llist
}

It seems to me that PersistentList and PersistentSet should provide an implementation for plusElement to help work around this long-standing resolution issue in the same fashion that the standard library collections do.

SebastianAigner commented 1 year ago

Just a personal opinion point on this as well: Intuitively, adding elements to a PersistentList feels much more like a plus operation than an add operation (add is a term that is used often times with mutable collections – and potentially with a return type of Boolean, whereas plus provides a hint that the result of the expression would likely be a 'new' collection reference).

It seems like plus (and the unfortunate plusElement) would actually already suffice, without an add function at all.