Am I correct that ‘coroutineScope’ function is the...
# coroutines
a
Am I correct that ‘coroutineScope’ function is the suspending equivalent of runBlocking? If so, wouldn’t it make more sense to have called it runSuspending?
s
To the first part of the question: yes, the analogy is good. Both functions create an encapsulated scope and then wait for it to complete. But as far as the naming is concerned, I don't know 🤷. Naming the two functions as if they form a pair might mislead people into thinking they should be used in similar ways. But in fact the use cases are quite different. I think it's good that the two names emphasize different aspects of the behaviour.
a
How are the use cases so different then?
s
• The
coroutineScope
function is for concurrent decomposition (also sometimes called parallel decomposition), and lets you break down a task into multiple concurrent subtasks. Because it encapsulates all of the coroutines that you launch inside it, and waits for them to complete or fail, the caller doesn't need to know anything about what's going on inside. It's like a coroutine "black box". From the point of view of the caller, a function that uses
coroutineScope
to decompose its execution into concurrent subtasks should be indistinguishable from any other
suspend
function. • The
runBlocking
is for bridging non-coroutine code with coroutine code. It should be used rarely and with caution. Generally it should only be used at application entrypoints. The crucial difference really comes down to composability. With
coroutineScope
, you split a coroutine into multiple coroutines, which means that each of those child coroutines can be further decomposed if you want. Whereas with
runBlocking
you transform a thread into one or more coroutines, which is a fundamental change of paradigm and is not composable.
To some extent I think the names reflect this stuff. For example
runBlocking
emphasises the fact that it blocks the thread, which is important because it highlights the fact that it should not be called from a coroutine and is thus not composable. The blocking is the important attribute. Whereas with
coroutineScope
, the suspending is less significant; the interesting thing is the decomposition and the encapsulated scope. That's just my take, though.
Certainly the names aren't perfect and reflect some historical quirks. I remember reading at one point that
runBlocking
would probably not be included at all if the coroutines API could be redesigned with the benefit of hindsight.
j
I was about to say exactly that. They behave similarly in practice, but they are used for very different cases that Sam described very neatly. I would add that renaming
coroutineScope
to
runSuspending
wouldn't make much sense. When calling
coroutineScope
we are already in a suspending context, so there is no point in a
runSuspending
. The point here is to create a coroutine scope locally in order to launch multiple concurrent child coroutines and wait for their result. The name puts the emphasis on that.
s
Probably also worth mentioning the issue of dispatchers, since
runBlocking
must create its own (by default) whereas
coroutineScope
simply inherits. The dispatcher used by
runBlocking
is a source of much woe 😬
j
Yes, not only dispatchers but the whole coroutine context in general.
coroutineScope
inherits the context from the current coroutine (because there is a current coroutine), while
runBlocking
creates a new context from scratch
s
Almost from scratch 😁 IIRC that turned out to be so problematic that the dispatcher was adjusted to account for nested calls to runBlocking 😬. But that is probably getting too deep for this thread. I just find it interesting as an example of the problems that runBlocking ends up causing.
j
True. But I had never heard about
runBlocking
being absent from coroutines if they were redesigned. Surely there would have been a way to bridge blocking and coroutine worlds
s
I can't remember where I read it, I'm sure it was in a GitHub thread somewhere. I keep hoping to stumble across it again. My preferred approach in an ideal world would be to always start with
suspend fun main
if coroutines are needed. But of course reality is never that easy.