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

Kevin Gorham

12/11/2019, 1:14 PM
This does not behave as I'd expect. Can anyone explain why the first example does not print
output
but the second, similar, example does? No permutation of yield, delay or sleep seems to get
output
to print in Example 1. Example 1 (always prints
start stop
):
Copy code
@Test
    fun testUnexpectedBehavior() = runBlocking {
        print("start")
        captureScope()
        scope.launch {
            print(" output")
        }
        print(" stop")
    }

    lateinit var scope: CoroutineScope
    suspend fun captureScope() = coroutineScope {
        scope = this
    }
Example 2 (always prints `start output stop`:
Copy code
@Test
    fun testExpectedBehavior() = runBlocking {
        print("start")
        coroutineScope {
            launch {
                print(" output")
            }
        }
        print(" stop")
    }
t

tseisel

12/11/2019, 2:07 PM
The
coroutineScope
function suspends the caller until all children coroutine have terminated. This means that in Example 2, "output" will always be printed before "stop". In Example 1, you are capturing the
CoroutineScope
from the
coroutineScope
block. Because that block has run to completion, its scope is finished and you cannot launch coroutines in it.
k

Kevin Gorham

12/11/2019, 2:26 PM
its scope is finished and you cannot launch coroutines in it
Interesting. This is the part that's surprising. It feels like in this case
scope.launch
should throw an exception. In a similar way that a cancelled job or channel would behave. I added some logs and confirmed your explanation at the time of `scope.launch`: • the job is not cancelled • but the job is not active • and the scope is not active So I think I had a gap in my understanding on how
isActive
behaves. I've only used it for cooperative cancellation but I've never observed how it behaves in this scenario. Thanks for the help! I'll look for some documentation on
isActive
.
b

bdawg.io

12/11/2019, 9:51 PM
In example 1,
output
should never be printed because the
captureScope
returns with
scope
being setting to a cancelled
CoroutineScope
because you're not launching inside of the
coroutineScope
lambda. There's no benefit to capturing the
CoroutineScope
because you already have one inside your
runBlocking
(suspending) lambda
4 Views