https://kotlinlang.org logo
#coroutines
Title
# coroutines
m

myanmarking

07/19/2022, 3:20 PM
If i have three flows that return boolean, what is the best operator equivalent to this: (if(aaa || bbb || ccc) ?
meaning, if a flow returns true along the way, use it. otherwise use the next
i can do it with chained flatMapLatest, but it seems weird
basically this
firstFlow
.flatMapLatest { condition ->
if (condition) {
flowOf(true)
} else {
secondFlow
.flatMapLatest { condition ->
if (condition) {
flowOf(true)
} else {
thirdFlow
}
}
}
}
c

curioustechizen

07/19/2022, 3:22 PM
Is your flow aaa a completing flow? And are you looking for it to complete before moving on to the next one?
m

myanmarking

07/19/2022, 3:22 PM
i don’t want want to use combine, because only one flow may be needed
it doesn’t complete, no
r

Robert Williams

07/19/2022, 3:44 PM
And it’s required that if
firstFlow
emits again once
secondFlow
is started you need to cancel
secondFlow
and maybe restart it (if still false)?
That’s what you’re currently getting with `flatMapLatest`; if you don’t need/ want that then things are much simpler
l

louiscad

07/19/2022, 4:14 PM
Sounds like you'd want
combine
but I'm not sure I understood what you want to do.
m

myanmarking

07/19/2022, 4:23 PM
Emit true if any of the flows emit true, minimizing flow collection. combine just works, but it collect the three needlesslly
l

louiscad

07/19/2022, 4:24 PM
You mean, you only care about the first value?
If so, it seems like you want to write
flowA.first() || flowB.first() || flowC.first()
m

myanmarking

07/19/2022, 4:26 PM
Wont work, the flows change
At any time, any1 can change to true.
Ill just use combine and shut up :p
r

Robert Williams

07/19/2022, 4:29 PM
Surely
merge
is more appropriate than
combine
?
At least that way you don’t have to wait for all flows to emit something?
m

myanmarking

07/19/2022, 4:31 PM
Good point. Thanks
l

louiscad

07/19/2022, 4:32 PM
Another idea:
Copy code
raceOf({
    flowA.first { it }
}, {
    flowB.first { it }
}, {
    flowC.first { it }
})
With
raceOf
as defined at the end of this article: https://blog.louiscad.com/coroutines-racing-why-and-how
m

myanmarking

07/19/2022, 4:35 PM
The resulting boolean is hot, not the first true
s

Stephen Edwards

07/19/2022, 8:13 PM
So
merge
makes sense but I don't understand your point here:
but it collect the three needlesslly
merge
would still collect all 3 so it can emit the latest value from any of them.
in other words, (A) you want 'one to win' and avoid waiting for that 'round' of booleans from all 3, or (B) which one 'wins' doesn't matter but you'll always be collecting from all three. It seems like you want (B) but then you mentioned that being inefficient and you wanted (A)?
n

natario1

07/19/2022, 10:06 PM
The original solution with flatMapLatest seems to be the best. It will look less weird if you avoid indenting the third flow, just chain it - first.or(second).or(third) (assuming you make an or operator that uses flatMapLatest)
r

Robert Williams

07/20/2022, 9:50 AM
I still don't really get the reasoning for wanting to delay collecting flows
Can you actually guarantee that one flow will be significantly faster than another?
If not, just merge them all and let the first one win
Even if so, the first one will win anyway (and others will be cancelled) so doesn't really matter
m

myanmarking

07/20/2022, 9:51 AM
merge won’t work. how do you single out the first ‘true’ using merge ? It’s a hot flow. Not only the first value is relevant
r

Robert Williams

07/20/2022, 9:53 AM
merge().filter(it).first()
m

myanmarking

07/20/2022, 9:53 AM
it is a hot flow! It cannot call first
the value can change
i’ll describe with a more realistic usecase 1s
Let’s say you have three queries: a) has apples (true/false), b) has oranges (true/false), c) has grapes (true/false). You want to observe ‘hasFruit’. You can combine the three, but if the first one returns true, you don’t need the second or the third. (combine will do it, i was just asking if there is a better approach)
r

Robert Williams

07/20/2022, 10:01 AM
Ah yeah, if you need the case where they go back to (false, false, false) then you'll need to wait for all of them
But depending on how the flows are implemented I'd expect the combine version would still perform better than the flatMapLatest version
Also depends on how often they change and how often they're true
l

louiscad

07/20/2022, 1:29 PM
I get your use case now @myanmarking. The thing is that to get to what you want, you'll need to trade latency and/or correctness for efficiency. It also depends on how long it takes for one of your flows to produce a value when they're subscribed to. If you have that info, it can be helpful for the specific flow operator you want to do.
3 Views