I was reading some source code on coroutines and run into this function;
private fun cancelParent(cause: Throwable): Boolean {
// CancellationException is considered "normal" and parent is not cancelled when child produces it.
// This allow parent to cancel its children (normally) without being cancelled itself, unless
// child crashes and produce some other exception during its completion.
if (cause is CancellationException) return true
if (!cancelsParent) return false
return parentHandle?.childCancelled(cause) == true
}
The point that I don't quite get is the very first line of code. It feels like it contradicts with what's stated in the comment. If the exception is CancellationException then it's a "normal" cancellation and the parent should not be cancelled, right? However, the function returns true which is read like - "Ok, I'm gonna cancel the parent".
By the way, the rest of the lines/checks in the function make sense to me when I look into what, for example supervisorScope or launch, returns.
Can someone please explain?
That's one of the cases where naming return values would be valuable.
If you look at the usage of this code, you'll see the following:
// Now handle the final exception
if (finalException != null) {
val handled = cancelParent(finalException) || handleJobException(finalException)
if (handled) (finalState as CompletedExceptionally).makeHandled()
}
So, true means not shouldParentBeCancelled?, as one may assume, but wasCancellationAlreadyHandledOrShouldBeHandledByParent?
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With