https://kotlinlang.org logo
Title
n

natario1

03/29/2023, 9:24 AM
Could someone please explain why do I see the
outerScope END
log in this example? https://pl.kotl.in/BMb6dLHG- It creates an outerScope, jumps on innerScope using
withContext
, then cancels outerScope while it’s running. Docs say:
Note that the result of
withContext
invocation is dispatched into the original context in a cancellable way with a prompt cancellation guarantee, which means that if the original coroutineContext in which
withContext
was invoked is cancelled by the time its dispatcher starts to execute the code, it discards the result of
withContext
and throws CancellationException.
So I would expect
withContext
to, basically, throw before returning.
s

Sam

03/29/2023, 9:29 AM
By passing a custom context (containing a custom Job) to
withContext
, you’re basically making it ignore cancellation of the outer scope. The behaviour is the same as if you wrote
withContext(NonCancellable)
.
n

natario1

03/29/2023, 9:31 AM
Yes, I understand why it won’t cancel while running (
innerScope END
line). But docs say it should throw before returning, after switching back to the outer context.
s

Sam

03/29/2023, 9:36 AM
In this case I think the key might be that the two contexts share the same dispatcher. There’s a note at the end of the docs:
The cancellation behaviour described above is enabled if and only if the dispatcher is being changed. For example, when using withContext(NonCancellable) { ... } there is no change in dispatcher and this call will not be cancelled neither on entry to the block inside withContext nor on exit from it.
I’m not 100% sure on that though. But I did notice that if you do change the dispatcher, it doesn’t print the
outerScope END
message.
n

natario1

03/29/2023, 9:39 AM
Ahh, that has to be the cause. Thanks a lot Sam. Not sure how I missed that note.
s

Sam

03/29/2023, 9:49 AM
It seems like an odd design choice 😞. Strange for the choice of dispatcher to affect the cancellation checks.
c

CLOVIS

03/29/2023, 9:51 AM
It's a performance optimization. If the dispatcher is the same, withContext does almost nothing: https://github.com/Kotlin/kotlinx.coroutines/blob/master/kotlinx-coroutines-core/common/src/Builders.common.kt#L149
n

natario1

03/29/2023, 9:54 AM
I too wish there was an ensureActive call when exiting.
c

CLOVIS

03/29/2023, 9:55 AM
I wonder why they didn't add one. Maybe this could be worth creating an issue to ask them to explain?
n

natario1

03/29/2023, 9:57 AM
Maybe it’s because most people will not pass a different Job to
withContext
, so the contents of withContext can already react to cancellation. But if job is different it would be nice to have one for consistency