kotlinx.coroutines icon indicating copy to clipboard operation
kotlinx.coroutines copied to clipboard

Add StateFlow<T>.onSubscription

Open xit0c opened this issue 1 year ago • 6 comments
trafficstars

Use case

The current SharedFlow<T>.onSubscription implementation returns a SharedFlow<T>, which means losing type information when calling it from a StateFlow<T>. It would be nice to have a StateFlow<T>.onSubscription counterpart for StateFlow<T>, thus avoiding the aforementioned issue.

The Shape of the API

Unless there are implementation details I'm unaware of, the API could be copy-pasted from the SharedFlow<T>.onSubscription implementation and adapted to work with StateFlow<T>:

public fun <T> StateFlow<T>.onSubscription(action: suspend FlowCollector<T>.() -> Unit): StateFlow<T> =
    SubscribedStateFlow(this, action)

@OptIn(ExperimentalForInheritanceCoroutinesApi::class)
private class SubscribedStateFlow<T>(
    private val stateFlow: StateFlow<T>,
    private val action: suspend FlowCollector<T>.() -> Unit
) : StateFlow<T> by stateFlow {
    override suspend fun collect(collector: FlowCollector<T>) =
        stateFlow.collect(SubscribedFlowCollector(collector, action))
}

Prior Art

xit0c avatar Nov 15 '24 17:11 xit0c

Sure, this makes sense, thanks! Would you like to open a PR with this code (+ documentation + tests)?

dkhalanskyjb avatar Feb 28 '25 10:02 dkhalanskyjb

I'd be glad to! I hope to deliver the changes in the next few days.

xit0c avatar Mar 03 '25 10:03 xit0c

Done!

The documentation is copy-pasted from SharedFlow<T>.onSubscription, I've only replaced the word "shared" with "state" in the first line.

About the tests, I saw that there's already testOnSubscriptionWithException (which now is using the new onSubscription), is it enough?

xit0c avatar Mar 09 '25 18:03 xit0c

Good job, thanks! Let's continue under https://github.com/Kotlin/kotlinx.coroutines/pull/4380, as this starts to be about the implementation and not the issue itself.

dkhalanskyjb avatar Mar 10 '25 11:03 dkhalanskyjb

Another useful thing to have would be to add onCompletion to StateFlow

lemberh avatar Jun 09 '25 18:06 lemberh

@lemberh, it wouldn't work. SharedFlow<T>.onCompletion(action) calls action when the consumer unsubscribes, but SharedFlow is a hot flow that emits values regardless of whether there are subscribers. A version that ignores consumers and just calls action when the flow completes makes even less sense, as SharedFlow<T> never completes.

dkhalanskyjb avatar Jun 10 '25 13:06 dkhalanskyjb