Avoiding mutation while working with collection

I have some code that needs to build a list over time. Once an element is added, it’s never changed, as it’s recording a history of events.

Wondering what’s the best way to build a collection over time without mutating that’s also performant?

Here’s something I tried that I think mutates only the list reference. Will Kotlin just link existing memory here, or will it actually create copies each time I add? Is there a better way to do this?

 data class Series<T,R> (val index: T, val value: R)
 typealias IntDouble = Series<Int,Double>
 typealias IntDoubleList = List<Series<Int,Double>>
 
 fun addToCollection(l: IntDoubleList, s: IntDouble) : IntDoubleList {
    return l + s
 }

 fun main() {
     val a = Series(1,3458.20)
     val b = Series(2,3457.40)
     val c = Series(3,3450.91)
     
     var seriesList = listOf(a,b,c)
     seriesList = addToCollection(seriesList, Series(4,3450.55))
 }

In this case it will copy the data on each new item.

What do you mean by saying that you need to do this “without mutating”? It sounds like: mutate without mutating.

I don’t say what you need doesn’t make sense at all - there are things like persistent collections, etc. I just think it is important to specify, what is your concern regarding making your collection a normally mutable list.

2 Likes

Ok. So it’s probably better to just use a mutable list here? Does using add() on a mutable list just link another element without any copying?

I’m just getting started coding in a more functional style so want to avoid mutation where it makes sense.

Thanks for the tip. Just found this:

If you don’t have a specific need to keep it immutable then I say yes: just make it mutable. Most of the time add() does not copy the data.

mutableListOf() (actually, ArrayList) allocates more space than it needs and then add() just puts the item into array at the next free index and increments the size marker. When it gets out of space, it allocates a new, bigger array (usually twice as big) and copies the data. This technique is pretty efficient for a general usage. And I believe it is faster than immutable/persistent collections for such use case as yours.

Yes, this is exactly the project I meant. If you’re into functional languages and “everything is immutable” paradigm then I guess this is what you need.

Sounds like you’re looking for something like a linked list?

    val linkedList = LinkedList<Double>()

    linkedList += 1_3458.20
    linkedList += 2_3457.40
    linkedList += 3_3450.91

It is mutable, but the append operation would be more efficient than using a mutableListOf that is backed by an ArrayList.

1 Like