Why Flow default operators does not expose the context?

Say in one of your map { } you need to start suspending calls and in the next map { } await() for them.

Surely you will need to start them async { }! But to do that you need to call coroutineScope { } inside the operator and it adds ugliness to the code by adding one more level of indentation to the already big indentation chain that often is any reactive stream (thought Kotlin Flows are very much less verbose, thank you JetBrains and people who helped the repository :heart:).

So question is, why did you choose to not expose the coroutine context in operators?

You always have access to the CoroutineContext with the coroutineContext method.

Read Coroutine Context and Scope and Explicit concurrencyfor the reasoning behind why you should use the coroutineScope method.

Basically, it’s easier to reason about code if suspend methods always finish any launched child jobs before they return.

I may have express myself not clearly!

I was looking for a solution to “zip” two suspending calls together the same way you would do with Observable’s Singles.zip(). I need to start those functions asynchronously and map their result once both are available!

With suspending calls this is possible by creating Deferreds of the calls and then await()ing them. To do so you need a CoroutineScope that is always available trough coroutineScope { } when inside a suspending context.

My question now is, why did the team behind Kotlin Coroutines decided to use regular lambdas instead of extensions lambdas with the context of the transformation? Check the example below:

I was just asking why map { } hasn’t this signature:

inline fun <T, R> Flow<T>.scopedMap(crossinline transform: suspend CoroutineScope.(value: T) -> R): Flow<R> = map { 
    coroutineScope { 
        transform(it)
    }
}

Of course you can recover the scope whenever you want, but that is another indentation level and it’s ugly! You can as well write down your scopedMap and use it.

Probably because it would be less performant for the sake of a seemingly rare use case that is trivial to implement by users if desired.

1 Like

Well, all of them are inlined so no performance loss at all, but I guess it’s still some added complexity.

Didn’t Elizarov’s post on Github answer to your question?

keep simple operators faster, and it is Ok if more complex operators have to use coroutineScope occasionally when they need it

1 Like

Oh damn, opening the link through Fasthub from mobile opened the thread from the beginning making me think that I missed the point with my first post! Thank you tho :slight_smile: