Is there a nice way to combine 2 state flows into ...
# coroutines
d
Is there a nice way to combine 2 state flows into another one without using
stateIn
which requires a
CoroutineScope
?
Copy code
val s1: StateFlow<Int>
val s2: StateFlow<Long>

val s3: StateFlow<Long> = combine(s1, s2) { v1, v2 ->
  v1.toLong() + v2
}
// ^^^ can't do that, combine results in `Flow<Long>`, 
// must do stateIn...
j
How exactly would you expect it to work? As soon as you do any transformation or combination, the resulting flow becomes cold again. In order to be a
StateFlow
it would need to have a value (the current state) at all times, accessible without suspension. This means that the value needs to be kept up-to-date.
stateIn
does exactly that: it launches a coroutine that reads from the source flow, and updates the current state. And to launch a coroutine... you need a scope
d
Indeed! Thank you. Sometimes I just stop thinking semantically and start to think purely on the type level so these details get lost...
j
Maybe a cold flow is sufficient for you, though
d
I'm bound by the interface which I have to implement and it has a
StateFlow
...
Will require a scope then, thanks.
g
Prefer exposing only cold flows everywhere where it possible, especially interfaces, it makes it more flexible (so implementation may be cold or ho, and allows consumers of those apis use their own scope to manage lifecycle
It's not a strong rule of course, sometimes you want state flow as API, but using cold flow is more reactive
d
Agreed. Initially I thought that exposing a
StateFlow
will highlight the contract to the consumer, i.e that this flow is conflating and always emits on subscription. But maybe I should cover that in docs instead and loosen this up...
g
Yes, you're right, it is exposing the contract, but this contract is just limiting implementation too much, for example force implementation provide some default value which may be not useful for consumer of the API, it's usually better to declare default on place of usage And often unnecessary for consumers to have this contract and even promotes non-reactive usage, which often will not work as expected
d
You can't, the code inside
combine
can still change threads so the combine value may be emitted later(ex: after 2 seconds)
g
can still change threads
Event without changing the thread you can just have delay() or any other suspend function
👍🏻 1