https://kotlinlang.org logo
Title
u

uli

05/24/2022, 6:24 AM
Hi all, is there any thing bad with a `collectIn`extension on Flow?
inline fun <reified T> Flow<T>.collectIn(scope: CoroutineScope, collector: FlowCollector<T>): Job {
    return scope.launch {
        collect(collector)
    }
}
It is so obvious, that I was thinking there must be something fundamentally broken if it is not part of the coroutines library.
1
u

uli

05/24/2022, 7:42 AM
no. I am looking for a terminal operator.
i.e. RxJava’s subscribe. Collect and launch at once.
j

Joffrey

05/24/2022, 7:45 AM
launchIn
is terminal. Usually this is done via `onEach`+
launchIn
.
🙌 1
u

uli

05/24/2022, 7:54 AM
Yes, I am aware of this pattern but would prefere a ‘terminal background collector’. To have the collector actually at the end of the operator chain:
flow
.map {
   ...
}
.collectIn(scope) { value ->
   consume(value)
}
s

stojan

05/24/2022, 7:58 AM
since your operator is similar to
launchIn
, there is nothing wrong with it. The KotlinX Coroutines lib typically goes with minimal APIs, so if you need a function like the one you mentioned, you can write it yourself for your project
u

uli

05/24/2022, 8:01 AM
@stojan yes, I can. That’s why I asked
is there any thing bad with a collectIn extension on Flow?
And explained:
It is so obvious, that I was thinking there must be something fundamentally broken if it is not part of the coroutines library.
So I take your answer to mean ‘it’s fine, library just decided to go another way’ ^^^ This is what your first sentence says
Thanks @stojan
Should be also a case for context receivers with the scope in context…
👍 2
a

Adam Powell

05/24/2022, 12:57 PM
APIs with this shape tend to prevent people from learning to think in suspend if they're new to it and have an Rx background. It's a useful utility if you know what you're doing, but newcomers tend to misread this code:
foo.collect {
  doStuff(it)
}

bar.collect {
  doOtherStuff(it)
}
and they assume the above runs the two collections concurrently rather than sequentially. Reinforcing that assumption from Rx prolongs that confusion
n

Nick Allen

05/24/2022, 11:37 PM
I've found the opposite. When you give people an operator that does what they want, they use it instead of misusing other operators. I've seen
onEach
mistaken for a terminal operator as often as I've seen
collect
mistaken for a concurrent non-suspending operator. Even knowing the API, It's easy to miss the
launchIn
just as basically a typo (which is what led me to always creating my own versions of
collectIn
operators). It's also odd since from my experience,
collect
is rarely useful. Most `Flow`s that I use never complete.
StateFlow
,
SharedFlow
,
callbackFlow
wrapping addListener/removeListener APIs, Room generated `Flow`s. 99% of the time I use my own
collectIn
.
collect
is front and center in the docs, but in practice for me, it's been something of a fringe use-case only really useful in creating my own custom operators here and there.
👍 1