Search code examples
kotlinkotlinx.coroutines

What's the difference between a "job + UI" context and using "parent = job"?


The UI Coroutines Guide contains a section on how to manage the lifecycle of UI coroutines. It explains we should create a top-level Job instance and pass a composite coroutine context, contextJob + UI to all coroutines we launch:

launch(contextJob + UI, block = block)

While implementing this pattern in my project it came natural to me to use contextJob as the parent instead:

launch(UI, parent = contextJob, block = block)

I haven't yet tested the difference in behavior, but I'm interested in the semantic difference between these two options. They look very similar to me, but I'd prefer to use the parent = contextJob since it's more obvious what it does. Specifically, I note that parent is allowed to be null, but if I use +, I would probably have to use NonCancellable as the null-object.

Is there anything wrong with using contextJob as the parent argument to launch or actor?


Solution

  • There is no semantic difference, neither there will be in the future.

    Ability to use + operator comes naturally from coroutineContext machinery: Job is context element, thus it can be appended to the context.

    But writing launch(UI + job) seems unnatural, because an intention is not clear. What does it even mean to have a concatenation of UI dispatcher and some job? To make such pattern readable, parent parameter was added, launch(UI, parent = job) is a more natural way to expose intention to launch job as a child of given parent. Under the hood, it still concatenates context and parent, but now API looks prettier for users.

    Note that same approach could be used for other library's elements, e.g. for CoroutineExceptionHandler, but it's a tradeoff: either you have a method with dozen of default parameters, of you sacrifice a readability and write launch(ctx + myExceptionHandler), so it was decided to introduce only parent parameter as a most common one.