Skip to content

Commit 0a07a72

Browse files
committed
Improve the explanation of how await throws exceptions
Fixes two issues: * It is surprising for some users that the same exception can be thrown several times. Clarified this point explicitly. * Due to #3658, `await` can throw `CancellationException` in several cases: when the `await` call is cancelled, or when the `Deferred` is cancelled. This is clarified with an example of how to handle this. Fixes #3937
1 parent cdfe07c commit 0a07a72

File tree

1 file changed

+27
-7
lines changed

1 file changed

+27
-7
lines changed

kotlinx-coroutines-core/common/src/Deferred.kt

+27-7
Original file line numberDiff line numberDiff line change
@@ -33,17 +33,37 @@ import kotlinx.coroutines.selects.*
3333
public interface Deferred<out T> : Job {
3434

3535
/**
36-
* Awaits for completion of this value without blocking a thread and resumes when deferred computation is complete,
37-
* returning the resulting value or throwing the corresponding exception if the deferred was cancelled.
36+
* Awaits for completion of this value without blocking the thread and returns the resulting value or throws
37+
* the exception if the deferred was cancelled.
38+
*
39+
* Unless cancelled, [await] will return the same result on each invocation:
40+
* if the [Deferred] completed successfully, [await] will return the same value every time;
41+
* if the [Deferred] completed exceptionally, [await] will rethrow the same exception.
42+
*
43+
* This suspending function is itself cancellable: if the [Job] of the current coroutine is cancelled or completed
44+
* while this suspending function is waiting, this function immediately resumes with [CancellationException].
45+
*
46+
* This means that [await] can throw [CancellationException] in two cases:
47+
* * if the coroutine in which [await] was called got cancelled,
48+
* * or if the [Deferred] itself got completed with a [CancellationException].
49+
*
50+
* In both cases, the [CancellationException] will cancel the coroutine calling [await], unless it's caught.
51+
* The following idiom may be helpful to avoid this:
52+
* ```
53+
* try {
54+
* deferred.await()
55+
* } catch (e: CancellationException) {
56+
* currentCoroutineContext().ensureActive() // throws if the current coroutine was cancelled
57+
* processException(e) // if this line executes, the exception is the result of `await` itself
58+
* }
59+
* ```
3860
*
39-
* This suspending function is cancellable.
40-
* If the [Job] of the current coroutine is cancelled or completed while this suspending function is waiting, this function
41-
* immediately resumes with [CancellationException].
4261
* There is a **prompt cancellation guarantee**. If the job was cancelled while this function was
4362
* suspended, it will not resume successfully. See [suspendCancellableCoroutine] documentation for low-level details.
4463
*
45-
* This function can be used in [select] invocation with [onAwait] clause.
46-
* Use [isCompleted] to check for completion of this deferred value without waiting.
64+
* This function can be used in [select] invocations with an [onAwait] clause.
65+
* Use [isCompleted] to check for completion of this deferred value without waiting, and
66+
* [join] to wait for completion without returning the result.
4767
*/
4868
public suspend fun await(): T
4969

0 commit comments

Comments
 (0)