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

Orhan Tozan

10/13/2020, 1:22 PM
Is
StateFlow<T>
mapping a planned feature? Right now I stick with Flow instead of StateFlow<T> because it stops me from doing something like this:
Copy code
// Example 1
val name: StateFlow<String> = ...
val greeting: StateFlow<String> = name.map { name ->
    "Hi, $name!"
}

// Example 2
val a: StateFlow<Int> = ...
val b: StateFlow<Int> = ...

val sum: StateFlow<Int> = combine(a, b) {a, b -> a + b }
j

Jan Skrasek

10/13/2020, 1:24 PM
map{}.stateIn(). will be available in 1.4.0-M1, released very soon, probably today.
o

Orhan Tozan

10/13/2020, 1:38 PM
I don't get why a CoroutineScope is required as a parameter
z

Zach Klippenstein (he/him) [MOD]

10/13/2020, 1:53 PM
Because the upstream collection can outlive any one particular downstream collector. The passed scope defines the lifetime of that upstream collection.
o

Orhan Tozan

10/13/2020, 2:02 PM
I'm sorry, I dont have really deep low level knowledge or coroutines, but doesn't your saying only apply to hot flows? I'm talking about a mapping a cold StateFlow, how is it different than mapping a regular Flow (where it doesnt need a CoroutineScope to define a mapping)
z

Zach Klippenstein (he/him) [MOD]

10/13/2020, 2:49 PM
Sharing operators effectively turn cold streams into hot streams. Consider this example, with a fake
shareInWithoutScope
operator:
Copy code
val upstream = flow {
  emit("starting")
  delay(1000)
  emit("finished")
}.shareInWithoutScope()

// First collector
launch { // this: scope1
  withTimeout(500) {
    upstream.collect {}
  }
}

// Second collector
launch {
  // this: scope2
  delay(250)
  upstream.collect {}
}
In order to collect upstream, the operator needs a scope to collect in. If this collection happens lazily, it could use the scope of the first collector (
scope1
). Then the second collector starts collecting in
scope2
after 250 ms, which is fine. Then, at 500 ms,
scope1
gets cancelled – but
scope2
is still collecting, so the upstream collector needs to keep running. So sharing operators can’t rely on their downstream collector scopes to manage the shared collection.
As for why there’s no
map
operator on
StateFlow
that preserves the
StateFlow
type itself, see the discussion on this issue: https://github.com/Kotlin/kotlinx.coroutines/issues/2081
o

Orhan Tozan

10/14/2020, 3:31 PM
Do you mean that stateIn() creates Hot flows? Why is that
z

Zach Klippenstein (he/him) [MOD]

10/14/2020, 5:23 PM
Yes - a hot stream is one that it is "active" independently of downstream subscribers (whether there are zero, one, or 500). This is exactly what "sharing" or "multicasting" does, by definition. It creates a single upstream connection that is share between all downstream subscribers. This makes the resulting stream hot. There are some gray areas: the resulting stream does act like a cold stream in that it will always emit a value to every subscriber on subscription, and if you're using reference counting, zero subscribers is treated differently than non-zero, but in general I think it's more accurate to say the returned flows are hot because they are relative to each downstream subscriber for most of their lifetimes.