Skip to content

Improve CoroutineScope extensions documentation #4269

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 7, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
63 changes: 51 additions & 12 deletions kotlinx-coroutines-core/common/src/CoroutineScope.kt
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,13 @@ public interface CoroutineScope {
* Adds the specified coroutine context to this scope, overriding existing elements in the current
* scope's context with the corresponding keys.
*
* This is a shorthand for `CoroutineScope(thisScope.coroutineContext + context)`.
* This is a shorthand for `CoroutineScope(thisScope.coroutineContext + context)` and can be used as
* a combinator with existing constructors:
* ```
* class MyActivity {
* val uiScope = MainScope() + CoroutineName("MyActivity")
* }
* ```
*/
public operator fun CoroutineScope.plus(context: CoroutineContext): CoroutineScope =
ContextScope(coroutineContext + context)
Expand Down Expand Up @@ -117,13 +123,30 @@ public fun MainScope(): CoroutineScope = ContextScope(SupervisorJob() + Dispatch
/**
* Returns `true` when the current [Job] is still active (has not completed and was not cancelled yet).
*
* Check this property in long-running computation loops to support cancellation:
* Coroutine cancallation [is cooperative](https://kotlinlang.org/docs/cancellation-and-timeouts.html#cancellation-is-cooperative)
* and normally, it's checked if a coroutine is cancelled when it *suspends*, for example,
* when trying to read from a [channel][kotlinx.coroutines.channels.Channel] that is empty.
*
* Sometimes, a coroutine does not need to perform suspending operations, but still wants to be cooperative
* and respect cancellation.
*
* The [isActive] property is inteded to be used for scenarios like this:
* ```
* while (isActive) {
* // do some computation
* val watchdogDispatcher = Dispatchers.IO.limitParallelism(1)
* fun backgroundWork() {
* println("Doing bookkeeping in the background in a non-suspending manner")
* Thread.sleep(100L) // Sleep 100ms
* }
* // Part of some non-trivial CoroutineScope-confined lifecycle
* launch(watchdogDispatcher) {
* while (isActive) {
* // Repetitively do some background work that is non-suspending
* backgroundWork()
* }
* }
* ```
*
* This function returns `true` if there is no [job][Job] in the scope's [coroutineContext][CoroutineScope.coroutineContext].
* This property is a shortcut for `coroutineContext.isActive` in the scope when
* [CoroutineScope] is available.
* See [coroutineContext][kotlin.coroutines.coroutineContext],
Expand Down Expand Up @@ -292,24 +315,40 @@ public fun CoroutineScope.cancel(cause: CancellationException? = null) {
public fun CoroutineScope.cancel(message: String, cause: Throwable? = null): Unit = cancel(CancellationException(message, cause))

/**
* Ensures that current scope is [active][CoroutineScope.isActive].
* Throws the [CancellationException] that was the scope's cancellation cause if the scope is no longer [active][CoroutineScope.isActive].
*
* If the job is no longer active, throws [CancellationException].
* If the job was cancelled, thrown exception contains the original cancellation cause.
* This function does not do anything if there is no [Job] in the scope's [coroutineContext][CoroutineScope.coroutineContext].
* Coroutine cancallation [is cooperative](https://kotlinlang.org/docs/cancellation-and-timeouts.html#cancellation-is-cooperative)
* and normally, it's checked if a coroutine is cancelled when it *suspends*, for example,
* when trying to read from a [channel][kotlinx.coroutines.channels.Channel] that is empty.
*
* Sometimes, a coroutine does not need to perform suspending operations, but still wants to be cooperative
* and respect cancellation.
*
* This method is a drop-in replacement for the following code, but with more precise exception:
* [ensureActive] function is inteded to be used for these scenarios and immediately bubble up the cancellation exception:
* ```
* if (!isActive) {
* throw CancellationException()
* val watchdogDispatcher = Dispatchers.IO.limitParallelism(1)
* fun backgroundWork() {
* println("Doing bookkeeping in the background in a non-suspending manner")
* Thread.sleep(100L) // Sleep 100ms
* }
* fun postBackgroundCleanup() = println("Doing something else")
* // Part of some non-trivial CoroutineScope-confined lifecycle
* launch(watchdogDispatcher) {
* while (true) {
* // Repeatatively do some background work that is non-suspending
* backgroundWork()
* ensureActive() // Bail out if the scope was cancelled
* postBackgroundCleanup() // Won't be invoked if the scope was cancelled
* }
* }
* ```
* This function does not do anything if there is no [Job] in the scope's [coroutineContext][CoroutineScope.coroutineContext].
*
* @see CoroutineScope.isActive
* @see CoroutineContext.ensureActive
*/
public fun CoroutineScope.ensureActive(): Unit = coroutineContext.ensureActive()


/**
* Returns the current [CoroutineContext] retrieved by using [kotlin.coroutines.coroutineContext].
* This function is an alias to avoid name clash with [CoroutineScope.coroutineContext] in a receiver position:
Expand Down