runCatchingCancellable

suspend fun <T> runCatchingCancellable(block: suspend () -> T): Result<T>

Like runCatching, but safe in suspend code: it never swallows the cancellation of the caller.

Returns Result.success with the value of block, or Result.failure with its exception. Use it wherever you would write runCatching around a suspend call.

Example

val state = runCatchingCancellable { api.fetchDashboard() }.fold(
onSuccess = { DashboardState.Content(it) },
onFailure = { DashboardState.Error(it) },
)

Compared with runCatching

runCatching also catches the CancellationException of a cancelled coroutine. The coroutine then keeps running after its scope was cancelled, for example on a screen that the user already left. runCatchingCancellable throws that cancellation on.

Cancellation

  • When the caller is cancelled, the cancellation is thrown, even when block turned it into another exception.

  • A CancellationException from inside block, while the caller is still active, becomes Result.failure. Examples: the timeout of a withTimeout inside block, or await() on a Deferred that other code cancelled.

See also


suspend fun <T, R> T.runCatchingCancellable(block: suspend T.() -> R): Result<R>

The receiver form of runCatchingCancellable: block runs with this as its receiver.

val config: Result<Config> =
rawJson.runCatchingCancellable { parseConfig(this) }

The cancellation rules are the same as for the form without a receiver.