10/26/2017, 11:06 PM
Can someone explain the reasoning behind this: "In particular, it means that a parent coroutine invoking join on a child coroutine that was started using launch(coroutineContext) { ... } builder throws CancellationException if the child had crashed, unless a non-standard CoroutineExceptionHandler if installed in the context." ? It seems unintuitive at best. It makes something like this:
val outerJob = launch(CommonPool) {
    val inner1 = launch(coroutineContext) { /* blah */ }
    val inner2 = launch(coroutineContext) { /* blah */ }
    // do more stuff
    select<Unit> {
        // These lines will actually throw a CancellationException if either of the inner jobs are completed exceptionally!!!
        inner1.onJoin { val reason = inner1.getCompletionException(); /* blah */ }
        inner2.onJoin { val reason = inner2.getCompletionException(); /* blah */ }

// Here I can call `outerJob.cancel()` to cancel everything
very awkward to write


10/27/2017, 9:27 AM
The children coroutines are designed to carry out a subtask on behalf of the parent. Just like you’d do with subroutines:
fun parentSub() {
    childSub() // do something for me
crashes, then
crashed too, unless it uses try/catch (exception handler)
So this behavior is designed to help handling common-case “for free” (without boilerplate)
If you have some complex exception-handling logic and you want to manually manage your child’s life-cycle, then you should not start them as your children. Do
. Then you can manage it all yourself (see if they crashed or not, join them, etc)


10/27/2017, 5:38 PM
Thanks for your reply; that makes more sense; I was thinking of the onJoin causing the throw but that's just coincidentally where it was suspended, makes sense!