Why does launch builder always adds Job to the new...
# coroutines
s
Why does launch builder always adds Job to the new scope even when the current scope (used to launch a coroutine) uses a SupervisorJob?
g
Because launch has own lifecycle and own scope for child coroutines which attached to parent, you can cancel this launch using Job that you received on launch start
s
Yeah, i meant why not use a new SupervisorJob when the parent scope is associated with one
Copy code
val scope = CoroutineScope( Dispatchers.Default + SupervisorJob() )

    with(scope) {

        launch {

            launch {
                delay(500)
                throw Exception()
            }

            launch {
                try {
                    delay(1000)
                    println("launch sibling")
                } catch (e: CancellationException) {
                    println("sibling launch cancel")
                }
            }

            delay(1000)
            println("launch parent")
        }
    }
outer launch uses SupervisorJob where as the nested ones uses Job. So when the nested ones fail, it defeats the point of SupervisorJob
In case of android, viewModelScope has SupervisorJob and in some cases could end up with nested coroutines
g
Yes, this is correct behavior
s
Is there a way to enforce supervisor behavior across all nested levels?
g
yes, start each of them in with own SupervisorJob
but I wouldn’t recommend it
this code is just not how real life code should look like
s
Okay, i tried launch( SupervisorJob() ) but that defeats structured concurrency (parent-child relation is lost)
g
yes, sure
you have to use supervisorScope builder
but It would look strange and it is by design, because it’s against recommended way to work with coroutines
s
It seems like if launch was designed to user Job/SupervisorJob based on the one in the scope, it would work just fine right?
g
Not sure that I understand question
s
If a coroutine is launched in a scope associated with SupervisorJob , then launched coroutine's child job too could have been a SupervisorJob.
g
What kind behavior do you expect?
s
This would have taken care of parent-child relation as well
g
then launched coroutine’s child job too could have been a SupervisorJob.
No! And it by desgin
s
I'm trying to understand the rationale behind that design. Any reason not to use SupervisorJob?
g
Because SupervisorJob is less safe and more error prone, you should take care on all exceptions and handle lifecycle of other coroutines
First what you should ask yourself “Why do you need SupervisorJob behavior”
s
Unidirectional cancel behavior irrespective of nested level of coroutines
g
it’s fine for some component with scope (like ViewModel) to run multiple coroutines and handle excceptions manually, you don’t want to cancel scope of this component, but on other levels it doesn’t needed in most cases and you just avoid running all those nested coroutines with
launch
s
I don't have a real application case though, just playing with it
g
a real application case though
Do you have at least some problem what you trying to solve in sample?
s
Nothing more than the code i shared.
Will keep an eye on this, if i ever run into nested needs
g
Nesting is fine, I just don’t see problem with this code
in terms of error handling
isn’t this what your tried to achieve in your first message in another thread: https://pl.kotl.in/S1j09dtYV
If you want to handle exception for each launch, no need to use CoroutineExceptionHandler, just use try/catch inside of launch
s
Not really. The other thread was just to figure out why the handler was ignored (no parent-child relation)
g
The other thread?
g
ahh
Yes, but with SupervisorJob handler is not ignored anymore
so you can handle any uncaught exception on level of your ViewModel
but for asyncronous jobs, like in this sample, I just don’t see any reason to use SupervisorJob or CoroutineExceptionHandler
s
Okay