Kevin Gorham
12/11/2019, 1:14 PMoutput 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):
@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`:
@Test
fun testExpectedBehavior() = runBlocking {
print("start")
coroutineScope {
launch {
print(" output")
}
}
print(" stop")
}tseisel
12/11/2019, 2:07 PMcoroutineScope 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.Kevin Gorham
12/11/2019, 2:26 PMits scope is finished and you cannot launch coroutines in itInteresting. 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.bdawg.io
12/11/2019, 9:51 PMoutput 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