What data type should I use when I want to have a ...
# coroutines
m
What data type should I use when I want to have a mutable list of elements, and the ability to have multiple listeners waiting for new elements being added? Kind of like a flow, but which starts enumerating elements from the start of the collection rather than when the flow starts. A Channel also won't work, as it has an internal buffer rather than keeping all elements.
s
One option would be to use a
MutableSharedFlow
with an infinite (well,
Int.MAX_VALUE
) replay cache.
Depending on the use case, though, I'd be tempted to use a
MutableStateFlow<List<T>>
, and just use its
update
function to replace the entire list each time it changes.
m
Unfortunately since I'm adding a lot of single elements, I'm worried about the cost of creating large lists, as well as race conditions when taking the current value and adding an element to it.
s
If you're adding a lot of elements,
MutableSharedFlow
is probably better 👍. The state flow approach is safe since
update
is atomic, but you're right it could get expensive to recreate the list each time.
d
What I would do is
MutableStateFlow<PersistentList>
(with
PersistentList
implementation from https://github.com/Kotlin/kotlinx.collections.immutable). Persistent collections support creating lists with new elements added efficiently, and there are no race conditions, as each persistent list is a separate object.
👍 1
Oh, if by race conditions, you mean that several threads may want to update the state flow, you need https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines.flow/-mutable-state-flow/compare-and-set.html
Though I'd probably wrap the persistent list into some other class to ensure that
===
is used to check for equality; comparing lists element-by-element may be too inefficient in your case.
m
If I use a Flow<List<T>> won't a collect receive the entire list every time instead of receiving only the newest element?
d
It will, yes. If you're interested in updates and not snapshots, @Sam's suggestion with an infinite replay cache does seem like a good solution to me.