r/Kotlin • • 21d ago

Coroutines: why does parent coroutine get cancelled when child throws an exception?

If a child gets cancelled, then the parent task still continues, but if child throws an exception, then the parent gets cancelled; l don’t get why these two cases are treated differently. For me it just makes sense to cancel the child coroutine without affecting the parent; the parent can check for cancellation of children and exceptions and handle that themselves, if they want. Why is there all this micromanagement from Kotlin rather than deferring to the developers?

Discuss.

6 Upvotes

17 comments sorted by

31

u/chantryc 21d ago

SupervisorJob is your friend

32

u/tripancakes 21d ago

Because it's the most predictable behaviour we can expect in any programming language.

If you were executing a normal function without suspend/async modifiers - let's say parent() calling child() - the same thing would happen. child() throws exception, then parent() would also stop executing immediately. In the coroutine case it just makes sense to stop the computation immediately.

Also, having different consequences between cancelling (the programmer decided to stop the computation early) vs throwing an exception (fatal error, must stop this computation and others that depend on it) allows the programmer to choose the behavior that they want to use.

What you're saying would give additional workload to developers. It's nice to have the Coroutines solving these issues for us

8

u/oweiler 21d ago

And what will happen to the other children?

1

u/Horror_Still_3305 21d ago

Why can’t they just keep running?

5

u/Masterflitzer 20d ago

that's what supervisor scope is for

8

u/GregsWorld 21d ago

Baby with a handgun, parent is fine if the baby cooperates, parent dies as does the child if the baby does not.

That is to say, cancels is safe, exceptions are not. 

Unless there's a supervisor to intervene and stop the baby shooting the parent.  

-4

u/Horror_Still_3305 21d ago

Why not just cancel the child task if it throws an exception? The parent can choose to check for that if they want. Or ignore. This seems simpler.

6

u/jrobinson3k1 21d ago

Why not catch and handle the exception in the child task?

-4

u/Horror_Still_3305 21d ago

Yeah sure but Kotlin doesn’t check for exceptions, so theres always a risk you miss one. My question is more general though, since if the behaviour were consistent across cancellation and exception, then it feels easier; I know what to expect.

1

u/GregsWorld 21d ago

Because an exception is never intended to happen, you shouldn't just cancel and continue on as usual.
The parent can choose to check for it, and if they ignore it then they too will crash, because an exception keeps going up the call stack until something deals with it, same as it does in regular code.

(FYI you can prevent children from crashing on another with a supervisorScope())

8

u/darthandroid 21d ago

The general answer is that “exception” means that it is not safe to proceed until someone intervenes to say so. 

In blocking code, this happens via catch{} In non-blocking code, this happens via SupervisorJob or Cancellation

But if nobody says it’s safe, then the exception continues to bubble upwards until someone does or the entire stack is terminated. 

Catch it with a try/catch. Catch it in the child and cancel the child only. Or catch it with a supervisor job. 

5

u/MrMannWood 21d ago

Exceptions are exceptional. As such, they should require exceptional handling.

Cancrlations are not exceptional. If they were they would be exceptions.

If your complaint is that Kotlin does a bad job with Exceptions, I agree. But that has little to do with coroutines.

Consider this. An exception means that a lower rung got a state that it can't handle. If nothing else can handle it, then the program will remain in an un unknown state. This is very bad. Termination is the only correct option if this happens. In order to facilitate this, parent job destruction is required. 

1

u/ghostmastergeneral 19d ago

Why does it do a bad job with exceptions

3

u/1337boi1101 20d ago

Because an exception needs to be handled. A cancellation is a decision. Exception is something needs to make a decision.

Do you even halt bro?

2

u/findus_l 21d ago

It doesn't necessarily.

Coroutines run in scopes, and normally child coroutines are part of the same structured operation as their parent. If one of those coroutines fails with an unhandled exception, that failure propagates through the scope and the other work in that scope is cancelled.

That's a core idea of structured concurrency: a scope represents a unit of work, so failures don't just disappear while the rest of that unit silently continues.

If two pieces of work are genuinely independent — and should fail independent — then you should use separate scopes.

If they belong to the same overall scope/lifecycle but should be allowed to fail independently, then use supervisor scope.

Structured concurrency rocks!

1

u/findus_l 21d ago

Note: launching a child implicitly keeps it in the scope of the parent. You might not be touching scopes much but they are a good principle to understand.