tezvyn:

Explain the difference between launch and async in Kotlin Coroutines

Curated by the Tezvyn teamSource: kotlinlang.orgbeginner
Explain the difference between launch and async in Kotlin Coroutines

This tests scope behavior and side effects versus results. A strong answer says launch returns a Job for side effects, async returns a Deferred for results, and both are scope children. A red flag is using async for all tasks or ignoring exception handling.

WHAT THIS TESTS: The interviewer wants to know if you understand structured concurrency and the semantic difference between fire-and-forget and result-bearing coroutine builders. This is not about memorizing API signatures; it is about knowing when to spawn a side effect versus when to compute a value asynchronously and how scope parent-child relationships govern lifecycle and error propagation.

A GOOD ANSWER COVERS: First, state that launch returns a Job and is used for side effects where the caller does not need a result back. Second, state that async returns a Deferred, which is a subtype of Job, and that you call await on it to receive the computed value. Third, emphasize that both are children of the CoroutineScope they are called on, meaning the scope cannot finish until they finish, and cancellation of the scope cancels them. Fourth, mention that structured concurrency rules apply to both: they inherit context, should not have their parent Job overridden, and their failures can propagate to the parent depending on whether the parent is a regular Job or a SupervisorJob.

COMMON WRONG ANSWERS: A red flag is saying async is just a faster or better version of launch. Another red flag is claiming that async does not participate in structured concurrency or that you can pass a custom Job into its context without breaking the parent-child relationship. Candidates also stumble by saying exceptions in async always crash the app; in reality, unhandled exceptions in async propagate through structured concurrency similarly to launch when you await, but the timing differs. Confusing the two often reveals a lack of production debugging experience.

LIKELY FOLLOW-UPS: The interviewer may ask what happens if you call await on a Deferred that was cancelled, or how exceptions propagate when multiple async calls run inside a supervisor scope. They might also ask why you should prefer coroutineScope builder with async for parallel decomposition instead of using GlobalScope, or how to handle the case where one async failure should not cancel its siblings.

ONE CONCRETE EXAMPLE: Imagine a screen that needs to load a user profile and a settings object simultaneously. You launch a coroutineScope block and inside it call val user = async { repository.fetchUser() } and val settings = async { repository.fetchSettings() }. Then you await both. If the scope is tied to a ViewModel lifecycle, both fetches cancel automatically when the ViewModel clears. If you had used launch for both, you would have no clean way to return the fetched objects to the caller.

Source: kotlinlang.org

Read the original → kotlinlang.org

Get five bites like this every day.

Tezvyn delivers a daily feed of 60-second tech bites with quizzes to lock in what you learn.