https://kotlinlang.org logo
Title
d

dimsuz

02/03/2022, 11:38 AM
Is there a nice way to combine 2 state flows into another one without using
stateIn
which requires a
CoroutineScope
?
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

Joffrey

02/03/2022, 11:51 AM
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

dimsuz

02/03/2022, 11:53 AM
Indeed! Thank you. Sometimes I just stop thinking semantically and start to think purely on the type level so these details get lost...
j

Joffrey

02/03/2022, 11:54 AM
Maybe a cold flow is sufficient for you, though
d

dimsuz

02/03/2022, 12:30 PM
I'm bound by the interface which I have to implement and it has a
StateFlow
...
Will require a scope then, thanks.
g

gildor

02/03/2022, 2:32 PM
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

dimsuz

02/03/2022, 3:01 PM
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

gildor

02/04/2022, 2:49 AM
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

Dragos Rachieru

02/04/2022, 8:36 AM
You can't, the code inside
combine
can still change threads so the combine value may be emitted later(ex: after 2 seconds)
g

gildor

02/04/2022, 9:02 AM
can still change threads
Event without changing the thread you can just have delay() or any other suspend function
👍🏻 1