From 191bedce20e3541ce142c40e9b2e81a61fa6d9fd Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 11:24:29 +0200 Subject: [PATCH 01/39] docs(coroutines-basics): Improve clarity and grammar Refined the wording for better readability and correctness. Added missing articles and restructured sentences to avoid splitting the infinitive. --- docs/topics/coroutines-basics.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topics/coroutines-basics.md b/docs/topics/coroutines-basics.md index 68a1a01957..5b467c58bf 100644 --- a/docs/topics/coroutines-basics.md +++ b/docs/topics/coroutines-basics.md @@ -212,8 +212,8 @@ Done ## An explicit job A [launch] coroutine builder returns a [Job] object that is a handle to the launched coroutine and can be -used to explicitly wait for its completion. For example, you can wait for completion of the child coroutine -and then print "Done" string: +used to wait for its completion explicitly. +For example, you can wait for the completion of the child coroutine and then print the "Done" string: ```kotlin import kotlinx.coroutines.* From 941e00791d9d9ee86e983abfbb49a87e1ab26fc7 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 12:30:02 +0200 Subject: [PATCH 02/39] docs(Yield.kt): Fix verb forms Corrected verb forms for grammatical accuracy. --- kotlinx-coroutines-core/common/src/Yield.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/Yield.kt b/kotlinx-coroutines-core/common/src/Yield.kt index 717a6c7000..36487501f9 100644 --- a/kotlinx-coroutines-core/common/src/Yield.kt +++ b/kotlinx-coroutines-core/common/src/Yield.kt @@ -6,8 +6,8 @@ import kotlin.coroutines.intrinsics.* /** * Suspends this coroutine and immediately schedules it for further execution. * - * A coroutine run uninterrupted on a thread until the coroutine *suspend*, - * giving other coroutines a chance to use that thread for their own computations. + * A coroutine runs uninterrupted on a thread until the coroutine suspends, + * giving other coroutines a chance to use that thread for their computations. * Normally, coroutines suspend whenever they wait for something to happen: * for example, trying to receive a value from a channel that's currently empty will suspend. * Sometimes, a coroutine does not need to wait for anything, From 43db7c7f22deb328ea954ed40837e3df954af3fb Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 13:32:32 +0200 Subject: [PATCH 03/39] docs(cancellation-and-timeouts): Improve punctuation Added missing commas for grammatical correctness. Ensured proper separation between clauses to enhance sentence flow. --- docs/topics/cancellation-and-timeouts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index ac99d5fee3..6b89ffd9aa 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -7,8 +7,8 @@ This section covers coroutine cancellation and timeouts. ## Cancelling coroutine execution -In a long-running application you might need fine-grained control on your background coroutines. -For example, a user might have closed the page that launched a coroutine and now its result +In a long-running application, you might need fine-grained control on your background coroutines. +For example, a user might have closed the page that launched a coroutine, and now its result is no longer needed and its operation can be cancelled. The [launch] function returns a [Job] that can be used to cancel the running coroutine: From ce692bd83f9b2952d7dad683f8845a9ffb2e8907 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 13:54:24 +0200 Subject: [PATCH 04/39] docs(cancellation-and-timeouts): Clarify cancellable computation approaches Refined the explanation of cancellable computation strategies for greater clarity and precision. - Expanded details on periodically invoking suspending functions. - Reworded sentence structure to improve readability. - Included explicit references to `ensureActive` to provide better guidance on checking cancellation status. --- docs/topics/cancellation-and-timeouts.md | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 6b89ffd9aa..cb8c4fa673 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -142,9 +142,12 @@ which does not rethrow [CancellationException]. ## Making computation code cancellable -There are two approaches to making computation code cancellable. The first one is to periodically -invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose. -The other one is to explicitly check the cancellation status. Let us try the latter approach. +There are two approaches to making computation code cancellable. +The first one is periodically invoking a suspending function that checks for cancellation. +There are the [yield] and [ensureActive](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html) +functions, which are great choices for that purpose. +The other one is explicitly checking the cancellation status using [isActive]. +Let us try the latter approach. Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it. @@ -158,7 +161,7 @@ fun main() = runBlocking { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop - // print a message twice a second + // prints a message twice a second if (System.currentTimeMillis() >= nextPrintTime) { println("job: I'm sleeping ${i++} ...") nextPrintTime += 500L From 3c558fcb8ef4d77fb43057f315c052de284eccaa Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 14:00:33 +0200 Subject: [PATCH 05/39] docs(cancellation-and-timeouts): Add a direct link to the `use` function for quick reference. --- docs/topics/cancellation-and-timeouts.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index cb8c4fa673..019465cebb 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -195,8 +195,10 @@ main: Now I can quit. ## Closing resources with finally Cancellable suspending functions throw [CancellationException] on cancellation, which can be handled in -the usual way. For example, the `try {...} finally {...}` expression and Kotlin's `use` function execute their -finalization actions normally when a coroutine is cancelled: +the usual way. +For example, +the `try {...} finally {...}` expression and Kotlin's [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html) +function execute their finalization actions normally when a coroutine is cancelled: ```kotlin import kotlinx.coroutines.* From f0b4040cbc1b256fa304a0f8096f4d665c20e0ae Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:49:01 +0200 Subject: [PATCH 06/39] docs(cancellation-and-timeouts): Correct grammar in compound adjectives Revised grammatical inconsistencies for improved clarity and correctness. - Changed `well-behaving` to `well-behaved` to use the correct past participle form in a compound adjective. - Remove an unnecessary "a" from "any kind of a communication channel" to ensure proper usage. --- docs/topics/cancellation-and-timeouts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 019465cebb..ff19c7cb87 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -246,7 +246,7 @@ main: Now I can quit. Any attempt to use a suspending function in the `finally` block of the previous example causes [CancellationException], because the coroutine running this code is cancelled. Usually, this is not a -problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a +problem, since all well-behaved closing operations (closing a file, cancelling a job, or closing any kind of communication channel) are usually non-blocking and do not involve any suspending functions. However, in the rare case when you need to suspend in a cancelled coroutine you can wrap the corresponding code in `withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows: From 8ea553b3a40e696f6f042ad1df7c08dabb5d142b Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 15:55:45 +0200 Subject: [PATCH 07/39] docs(cancellation-and-timeouts): Add reference to TimeoutCancellationException --- docs/topics/cancellation-and-timeouts.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index ff19c7cb87..519b6538c2 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -332,7 +332,7 @@ Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Time -The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException]. +The [TimeoutCancellationException] that is thrown by [withTimeout] is a subclass of [CancellationException]. We have not seen its stack trace printed on the console before. That is because inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion. However, in this example we have used `withTimeout` right inside the `main` function. From 2654c94a1096973256a4f0cf53c9642972a0e2ea Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 16:11:00 +0200 Subject: [PATCH 08/39] docs(composing-suspending-functions): Enhance note visibility with styling Applied a note style to improve visibility and ensure that important information stands out more clearly in the documentation. --- docs/topics/composing-suspending-functions.md | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md index 7e8c249f21..d422c14bc6 100644 --- a/docs/topics/composing-suspending-functions.md +++ b/docs/topics/composing-suspending-functions.md @@ -182,11 +182,14 @@ So, here the two coroutines are defined but not executed as in the previous exam the programmer on when exactly to start the execution by calling [start][Job.start]. We first start `one`, then start `two`, and then await for the individual coroutines to finish. -Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual -coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine -execution and waits for its finish, which is not the intended use-case for laziness. -The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the -standard `lazy` function in cases when computation of the value involves suspending functions. +> Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual +> coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine +> execution and waits for its finish, which is not the intended use-case for laziness. +> The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the +> standard [lazy](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html) function in cases +> when computation of the value involves suspending functions. +> +{style="note"} ## Async-style functions From 674ce13fa6da38e50abcadebabff9c1b4a5010a6 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 16:21:33 +0200 Subject: [PATCH 09/39] docs(composing-suspending-functions): Clarify concurrent function extraction with coroutineScope example - Improve readability of async and coroutineScope explanation - Simplify language while maintaining technical accuracy - Restructure sentence flow for better comprehension --- docs/topics/composing-suspending-functions.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md index d422c14bc6..4877d8c12a 100644 --- a/docs/topics/composing-suspending-functions.md +++ b/docs/topics/composing-suspending-functions.md @@ -294,10 +294,10 @@ concurrency, as shown in the section below. ## Structured concurrency with async -Let us take the [Concurrent using async](#concurrent-using-async) example and extract a function that -concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results. -Because the [async] coroutine builder is defined as an extension on [CoroutineScope], we need to have it in the -scope and that is what the [coroutineScope][_coroutineScope] function provides: +Let's refactor the [Concurrent using async](#concurrent-using-async) example into a function that runs +`doSomethingUsefulOne` and `doSomethingUsefulTwo` concurrently and returns their combined results. +Since [async] is a [CoroutineScope] extension, +we'll use the [coroutineScope][_coroutineScope] function to provide the necessary scope: ```kotlin suspend fun concurrentSum(): Int = coroutineScope { From 3ad98101bb170b88248520ce316e49c2c85fb5e7 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sat, 8 Feb 2025 17:59:15 +0200 Subject: [PATCH 10/39] docs(coroutine-context-and-dispatchers): Improve explanation for context switching Refined the explanation of coroutine context switching for better clarity and comprehension. - Expanded details on `runBlocking` with an explicit context to highlight its controlled execution benefits. - Clarified how `withContext` suspends a coroutine and switches execution context while ensuring smooth reversion. - Structured the explanation for improved readability and understanding. --- .../coroutine-context-and-dispatchers.md | 27 +++++++++++++++---- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 89498af00e..e01b07bed8 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -246,9 +246,21 @@ fun main() { > {style="note"} -It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and -the other one is using the [withContext] function to change the context of a coroutine while still staying in the -same coroutine, as you can see in the output below: +The example above demonstrates two important techniques in coroutine usage. + +The first technique involves using [runBlocking] with an explicitly specified context. +This ensures that the coroutine runs in a controlled environment, +allowing you to define the execution context explicitly. + +The second technique uses the [withContext] function. +When you call [withContext], it suspends the current coroutine and switches to a new context. +This transition may involve changing the dispatcher or updating other context elements. + +After switching, the block of code executes within the newly specified context. +Once it completes, the coroutine automatically reverts to its original context, +ensuring a smooth and controlled execution flow. + +As a result, the output of the above code is: ```text [Ctx1 @coroutine#1] Started in ctx1 @@ -258,8 +270,13 @@ same coroutine, as you can see in the output below: -Note that this example also uses the `use` function from the Kotlin standard library to release threads -created with [newSingleThreadContext] when they are no longer needed. +The example above uses the [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html) function from the Kotlin standard library +to properly release thread resources created by [newSingleThreadContext] when they're no longer needed. + +>Note that [withContext] doesn't create a new coroutine - +>it merely provides a [CoroutineScope] with the specified context. +> +{style="note"} ## Job in the context From ee6b67221c33bc108dbb9064d7dfe0ea84c292fb Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 08:30:33 +0200 Subject: [PATCH 11/39] docs(Job): Improve readability and formatting Refined the documentation to enhance clarity and structure. - Improved sentence flow and paragraph formatting for better readability. - Reformatted explanations of job states and transitions for improved comprehension. - Enhanced descriptions of cancellation behavior to clarify distinctions between normal cancellation and failure. --- kotlinx-coroutines-core/common/src/Job.kt | 74 ++++++++++++++--------- 1 file changed, 45 insertions(+), 29 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt index 27665f6eef..451235dd22 100644 --- a/kotlinx-coroutines-core/common/src/Job.kt +++ b/kotlinx-coroutines-core/common/src/Job.kt @@ -11,23 +11,28 @@ import kotlin.jvm.* // --------------- core job interfaces --------------- /** - * A background job. Conceptually, a job is a cancellable thing with a life-cycle that - * culminates in its completion. + * A background job. + * Conceptually, a job is a cancellable thing with a lifecycle that + * concludes in its completion. * - * Jobs can be arranged into parent-child hierarchies where cancellation - * of a parent leads to immediate cancellation of all its [children] recursively. + * Jobs can be arranged into parent-child hierarchies where the cancellation + * of a parent leads to the immediate cancellation of all its [children] recursively. * Failure of a child with an exception other than [CancellationException] immediately cancels its parent and, - * consequently, all its other children. This behavior can be customized using [SupervisorJob]. + * consequently, all its other children. + * This behavior can be customized using [SupervisorJob]. * - * The most basic instances of `Job` interface are created like this: + * The most basic instances of the `Job` interface are created like this: * - * - **Coroutine job** is created with [launch][CoroutineScope.launch] coroutine builder. - * It runs a specified block of code and completes on completion of this block. - * - **[CompletableJob]** is created with a `Job()` factory function. + * - A **coroutine job** is created with the [launch][CoroutineScope.launch] coroutine builder. + * It runs a specified block of code and completes upon completion of this block. + * - **[CompletableJob]** is created with a [Job()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html) + * factory function. * It is completed by calling [CompletableJob.complete]. * - * Conceptually, an execution of a job does not produce a result value. Jobs are launched solely for their - * side effects. See [Deferred] interface for a job that produces a result. + * Conceptually, an execution of a job does not produce a result value. + * Jobs are launched solely for their + * side effects. + * See the [Deferred] interface for a job that produces a result. * * ### Job states * @@ -42,22 +47,30 @@ import kotlin.jvm.* * | _Cancelled_ (final state) | `false` | `true` | `true` | * | _Completed_ (final state) | `false` | `true` | `false` | * - * Usually, a job is created in the _active_ state (it is created and started). However, coroutine builders + * + * Note that these states are mentioned in italics below to make them easier to distinguish. + * + * Usually, a job is created in the _active_ state (it is created and started). + * However, coroutine builders * that provide an optional `start` parameter create a coroutine in the _new_ state when this parameter is set to - * [CoroutineStart.LAZY]. Such a job can be made _active_ by invoking [start] or [join]. + * [CoroutineStart.LAZY]. + * Such a job can be made _active_ by invoking [start] or [join]. * - * A job is _active_ while the coroutine is working or until [CompletableJob] is completed, - * or until it fails or cancelled. + * A job is in the _active_ state while the coroutine is working until the [CompletableJob] completes, + * fails, or is cancelled. * - * Failure of an _active_ job with an exception makes it _cancelling_. - * A job can be cancelled at any time with [cancel] function that forces it to transition to - * the _cancelling_ state immediately. The job becomes _cancelled_ when it finishes executing its work and + * Failure of an _active_ job with an exception transitions the state to the _cancelling_ state. + * A job can be cancelled at any time with the [cancel] function that forces it to transition to + * the _cancelling_ state immediately. + * The job becomes _cancelled_ when it finishes executing its work and * all its children complete. * * Completion of an _active_ coroutine's body or a call to [CompletableJob.complete] transitions the job to - * the _completing_ state. It waits in the _completing_ state for all its children to complete before + * the _completing_ state. + * It waits in the _completing_ state for all its children to complete before * transitioning to the _completed_ state. - * Note that _completing_ state is purely internal to the job. For an outside observer a _completing_ job is still + * Note that _completing_ state is purely internal to the job. + * For an outside observer, a _completing_ job is still * active, while internally it is waiting for its children. * * ``` @@ -82,18 +95,21 @@ import kotlin.jvm.* * * A coroutine job is said to _complete exceptionally_ when its body throws an exception; * a [CompletableJob] is completed exceptionally by calling [CompletableJob.completeExceptionally]. - * An exceptionally completed job is cancelled and the corresponding exception becomes the _cancellation cause_ of the job. - * - * Normal cancellation of a job is distinguished from its failure by the type of this exception that caused its cancellation. - * A coroutine that threw [CancellationException] is considered to be _cancelled normally_. - * If a cancellation cause is a different exception type, then the job is considered to have _failed_. - * When a job has _failed_, then its parent gets cancelled with the exception of the same type, + * An exceptionally completed job is cancelled, + * and the corresponding exception becomes the _cancellation cause_ of the job. + * + * Normal cancellation of a job is distinguished from its failure by the exception + * that caused its cancellation. + * A coroutine that throws a [CancellationException] is considered to be _cancelled_ normally. + * If a different exception causes the cancellation, then the job has _failed_. + * When a job has _failed_, its parent gets cancelled with the same type of exception, * thus ensuring transparency in delegating parts of the job to its children. * - * Note, that [cancel] function on a job only accepts [CancellationException] as a cancellation cause, thus + * Note, that the [cancel] function on a job only accepts a [CancellationException] as a cancellation cause, thus * calling [cancel] always results in a normal cancellation of a job, which does not lead to cancellation - * of its parent. This way, a parent can [cancel] its own children (cancelling all their children recursively, too) - * without cancelling itself. + * of its parent. + * This way, a parent can [cancel] his children (cancelling all their children recursively, too) + * without cancelling himself. * * ### Concurrency and synchronization * From b73a1d9aab43b267660dfced04d75de2977c5899 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 08:54:52 +0200 Subject: [PATCH 12/39] docs(CompletableJob.kt): Improve clarity and grammar MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Refined the documentation for `completeExceptionally` to enhance clarity and correctness. - Improved sentence structure for better readability. - Clarified the transition states of a job when completed exceptionally. - Fixed grammatical inconsistencies, such as "its responsibility" → "It is the responsibility." - Enhanced explanation of how children receive `CancellationException` for diagnostic purposes. --- kotlinx-coroutines-core/common/src/CompletableJob.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/CompletableJob.kt b/kotlinx-coroutines-core/common/src/CompletableJob.kt index b484bebee7..a793acc40c 100644 --- a/kotlinx-coroutines-core/common/src/CompletableJob.kt +++ b/kotlinx-coroutines-core/common/src/CompletableJob.kt @@ -32,12 +32,13 @@ public interface CompletableJob : Job { * * Subsequent invocations of this function have no effect and always produce `false`. * - * This function transitions this job into _cancelled_ state if it was not completed or cancelled yet. - * However, that if this job has children, then it transitions into _cancelling_ state and becomes _cancelled_ + * This function transitions this job into the _cancelled_ state if it has not been _completed_ or _cancelled_ yet. + * However, if this job has children, then it transitions into the _cancelling_ state and becomes _cancelled_ * once all its children are [complete][isCompleted]. See [Job] for details. * - * Its responsibility of the caller to properly handle and report the given [exception], all job's children will receive - * a [CancellationException] with the [exception] as a cause for the sake of diagnostic. + * It is the responsibility of the caller to properly handle and report the given [exception]. + * All the job’s children will receive a [CancellationException] with + * the [exception] as a cause for the sake of diagnosis. */ public fun completeExceptionally(exception: Throwable): Boolean } From 1fabd23bff4307155ec97b0940e8b051851196aa Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 09:04:15 +0200 Subject: [PATCH 13/39] docs(SupervisorJob()): Add a missing article. --- kotlinx-coroutines-core/common/src/Supervisor.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlinx-coroutines-core/common/src/Supervisor.kt b/kotlinx-coroutines-core/common/src/Supervisor.kt index c1d2145680..9c413b07b5 100644 --- a/kotlinx-coroutines-core/common/src/Supervisor.kt +++ b/kotlinx-coroutines-core/common/src/Supervisor.kt @@ -20,7 +20,7 @@ import kotlin.jvm.* * - A failure of a child job that was created using [launch][CoroutineScope.launch] can be handled via [CoroutineExceptionHandler] in the context. * - A failure of a child job that was created using [async][CoroutineScope.async] can be handled via [Deferred.await] on the resulting deferred value. * - * If a [parent] job is specified, then this supervisor job becomes a child job of [parent] and is cancelled when the + * If a [parent] job is specified, then this supervisor job becomes a child job of the [parent] and is cancelled when the * parent fails or is cancelled. All this supervisor's children are cancelled in this case, too. */ @Suppress("FunctionName") From b732faf5bab25f4da4a33fc01d4de4c642eb8032 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 09:45:59 +0200 Subject: [PATCH 14/39] docs(coroutine-context-and-dispatchers): Remove an unnecessary article. --- docs/topics/coroutine-context-and-dispatchers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index e01b07bed8..10a2b80861 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -298,7 +298,7 @@ fun main() = runBlocking { > {style="note"} -In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this: +In [debug mode](#debugging-coroutines-and-threads), it outputs something like this: ``` My job is "coroutine#1":BlockingCoroutine{Active}@6d311334 From c8bdcae6e6b302d33a0c4f4b425ba42d8ad1aafb Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 09:57:52 +0200 Subject: [PATCH 15/39] docs(coroutine-context-and-dispatchers): Fix a typo and remove redundant words. --- docs/topics/coroutine-context-and-dispatchers.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 10a2b80861..3def87ab68 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -317,12 +317,13 @@ the [Job] of the new coroutine becomes a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children are recursively cancelled, too. -However, this parent-child relation can be explicitly overriden in one of two ways: +However, this parent-child relation can be explicitly overridden in one of two ways: 1. When a different scope is explicitly specified when launching a coroutine (for example, `GlobalScope.launch`), - then it does not inherit a `Job` from the parent scope. -2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below), - then it overrides the `Job` of the parent scope. +it does not inherit a `Job` from the parent scope. + +2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below), +it overrides the `Job` of the parent scope. In both cases, the launched coroutine is not tied to the scope it was launched from and operates independently. From 4a08df9dc3269d847dc5e30fad3662d42a66f475 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 10:00:01 +0200 Subject: [PATCH 16/39] docs(coroutine-context-and-dispatchers): Add missing article --- docs/topics/coroutine-context-and-dispatchers.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 3def87ab68..5125a090db 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -374,7 +374,8 @@ job1: I am not affected by cancellation of the request ## Parental responsibilities -A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track +A parent coroutine always waits for the completion of all its children. +A parent does not have to explicitly track all the children it launches, and it does not have to use [Job.join] to wait for them at the end: ```kotlin From 4ea9dab1570b37ad1f145132db8001a7c28687db Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 10:19:49 +0200 Subject: [PATCH 17/39] docs(coroutine-context-and-dispatchers): Improve readability and clarity - Refined the explanation of `CoroutineScope` and its role in managing coroutine lifecycles. - Adjusted phrasing to provide a smoother flow and better comprehension. --- .../coroutine-context-and-dispatchers.md | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 5125a090db..29f702be96 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -499,11 +499,14 @@ I'm working in thread DefaultDispatcher-worker-1 @test#2 ## Coroutine scope -Let us put our knowledge about contexts, children and jobs together. Assume that our application has -an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application -and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch -and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed -to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity +Let us put our knowledge about contexts, children, and jobs together. +Assume that our application has an object with a lifecycle, but that object is not a coroutine. +For example, +we are writing an Android application, +and we launched various coroutines in the context of an Android activity to perform asynchronous operations to fetch +and update data, do animations, etc. These coroutines must be cancelled when the activity is destroyed +to avoid memory leaks. +We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope]. You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it. @@ -540,8 +543,9 @@ For the demo, we launch ten coroutines that delay for a different time: ``` In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms. -This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction -of the activity no more messages are printed, even if we wait a little longer. +This cancels the coroutines that were launched from `doSomething`. +We can see that because after the destruction +of the activity, no more messages are printed, even if we wait a little longer. From f62f85aaf95adb2fa9e26ebc1df0fa18c4beb510 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 10:31:21 +0200 Subject: [PATCH 18/39] docs(coroutine-context-and-dispatchers): Corrected minor grammatical inconsistencies and enhanced the flow --- docs/topics/coroutine-context-and-dispatchers.md | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 29f702be96..cda33b8464 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -609,7 +609,7 @@ by a single invocation of `job.cancel()` in `Activity.destroy()`. ### Thread-local data -Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines. +Sometimes it is convenient to be able to pass some thread-local data to or between coroutines. However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually. For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html), @@ -643,8 +643,8 @@ fun main() = runBlocking { > {style="note"} -In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so -it works on a different thread from the thread pool, but it still has the value of the thread local variable +In this example, we launch a new coroutine in a background thread pool using [Dispatchers.Default], so +it works on a different threads from the thread pool, but it still has the value of the thread local variable that we specified using `threadLocal.asContextElement(value = "launch")`, no matter which thread the coroutine is executed on. Thus, the output (with [debug](#debugging-coroutines-and-threads)) is: @@ -659,7 +659,7 @@ Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value: It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may -then have an unexpected value, if the thread running the coroutine is different. +then have an unexpected value if the thread running the coroutine is different. To avoid such situations, it is recommended to use the [ensurePresent] method and fail-fast on improper usages. @@ -669,11 +669,12 @@ It has one key limitation, though: when a thread-local is mutated, a new value i Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details. Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn, -stored in a thread-local variable. However, in this case you are fully responsible to synchronize +stored in a thread-local variable. +However, in this case, you are fully responsible to synchronize potentially concurrent modifications to the variable in this mutable box. -For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries -which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface +For advanced usage, for example, for integration with logging MDC, transactional contexts or any other libraries +that internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface that should be implemented. From 984e8cecaf8c66f43f18d0cc13e4063c5374a14c Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 10:58:20 +0200 Subject: [PATCH 19/39] docs(coroutine-context-and-dispatchers): Replace the incorrect call to the appropriate method --- docs/topics/coroutine-context-and-dispatchers.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index cda33b8464..25accd0883 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -600,9 +600,9 @@ Destroying activity! As you can see, only the first two coroutines print a message and the others are cancelled -by a single invocation of `job.cancel()` in `Activity.destroy()`. +by a single invocation of [`mainScope.cancel()`][CoroutineScope.cancel] in `Activity.destroy()`. -> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle. +> Note that Android has first-party support for coroutine scope in all entities with the lifecycle. > See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope). > {style="note"} From f17954a546adedb459da63bbd8608d58eb161dd3 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 11:26:48 +0200 Subject: [PATCH 20/39] docs(CoroutineScope.kt): Add missing articles and link to CoroutineScope() Added missing articles for improved grammatical accuracy and readability. Included a direct link to the `CoroutineScope()` function to enhance navigation and accessibility for developers. --- .../common/src/CoroutineScope.kt | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt index 973429ca06..68e527cf71 100644 --- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt +++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt @@ -158,14 +158,14 @@ public val CoroutineScope.isActive: Boolean /** * A global [CoroutineScope] not bound to any job. - * Global scope is used to launch top-level coroutines which are operating on the whole application lifetime + * Global scope is used to launch top-level coroutines operating on the application lifetime * and are not cancelled prematurely. * * Active coroutines launched in `GlobalScope` do not keep the process alive. They are like daemon threads. * * This is a **delicate** API. It is easy to accidentally create resource or memory leaks when * `GlobalScope` is used. A coroutine launched in `GlobalScope` is not subject to the principle of structured - * concurrency, so if it hangs or gets delayed due to a problem (e.g. due to a slow network), it will stay working + * concurrency, so if it hangs or gets delayed due to a problem (e.g., due to a slow network), it will stay working * and consuming resources. For example, consider the following code: * * ``` @@ -177,13 +177,14 @@ public val CoroutineScope.isActive: Boolean * } * ``` * - * A call to `loadConfiguration` creates a coroutine in the `GlobalScope` that works in background without any - * provision to cancel it or to wait for its completion. If a network is slow, it keeps waiting in background, + * A call to `loadConfiguration` creates a coroutine in the `GlobalScope` that works in the background without any + * provision to cancel it or to wait for its completion. If a network is slow, it keeps waiting in the background, * consuming resources. Repeated calls to `loadConfiguration` will consume more and more resources. * * ### Possible replacements * - * In many cases uses of `GlobalScope` should be removed, marking the containing operation with `suspend`, for example: + * In many circumstances, uses of 'GlobalScope' should be removed, + * with the containing operation marked as 'suspend', for example: * * ``` * suspend fun loadConfiguration() { @@ -206,14 +207,15 @@ public val CoroutineScope.isActive: Boolean * ``` * * In top-level code, when launching a concurrent operation from a non-suspending context, an appropriately - * confined instance of [CoroutineScope] shall be used instead of a `GlobalScope`. See docs on [CoroutineScope] for + * confined instance of [CoroutineScope] shall be used instead of `GlobalScope`. See docs on [CoroutineScope] for * details. * - * ### GlobalScope vs custom scope + * ### GlobalScope vs. Custom CoroutineScope * * Do not replace `GlobalScope.launch { ... }` with `CoroutineScope().launch { ... }` constructor function call. * The latter has the same pitfalls as `GlobalScope`. See [CoroutineScope] documentation on the intended usage of - * `CoroutineScope()` constructor function. + * [CoroutineScope()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html) + * constructor function. * * ### Legitimate use-cases * From 4249c7f745c7154feae1477fa3e01f26393a8e8b Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 11:32:52 +0200 Subject: [PATCH 21/39] docs(ThreadContextElement.kt): Add missing articles --- kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index c1898fbd65..b02b0a0b34 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -188,10 +188,10 @@ public interface CopyableThreadContextElement : ThreadContextElement { /** * Wraps [ThreadLocal] into [ThreadContextElement]. The resulting [ThreadContextElement] - * maintains the given [value] of the given [ThreadLocal] for coroutine regardless of the actual thread its is resumed on. - * By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with [value] parameter. - * Beware that context element **does not track** modifications of the thread-local and accessing thread-local from coroutine - * without the corresponding context element returns **undefined** value. See the examples for a detailed description. + * maintains the given [value] of the given [ThreadLocal] for a coroutine regardless of the actual thread it is resumed on. + * By default [ThreadLocal.get] is used as a value for the thread-local variable, but it can be overridden with the [value] parameter. + * Beware that the context element **does not track** modifications of the thread-local and accessing thread-local from a coroutine + * without the corresponding context element returns an **undefined** value. See the examples for a detailed description. * * * Example usage: From f08f0ff7cb60ffffb2d36671328baa0941c3272b Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 11:41:32 +0200 Subject: [PATCH 22/39] docs(ThreadContextElement.kt): Add a missing article and adjust wording for better clarity --- kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index b02b0a0b34..89a5aa3840 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -4,11 +4,12 @@ import kotlinx.coroutines.internal.* import kotlin.coroutines.* /** - * Defines elements in [CoroutineContext] that are installed into thread context + * Defines elements in a [CoroutineContext] that are installed into the thread context * every time the coroutine with this element in the context is resumed on a thread. * * Implementations of this interface define a type [S] of the thread-local state that they need to store on - * resume of a coroutine and restore later on suspend. The infrastructure provides the corresponding storage. + * upon resuming a coroutine and restore later upon suspension. + * The infrastructure provides the corresponding storage. * * Example usage looks like this: * From 242062171a3c65ac924556658f55c039744c5e78 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Sun, 9 Feb 2025 12:07:21 +0200 Subject: [PATCH 23/39] feat: Add the updated files generated by the Knit tool. --- docs/topics/cancellation-and-timeouts.md | 1 + docs/topics/coroutine-context-and-dispatchers.md | 1 + kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt | 2 +- 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 519b6538c2..89bb70a3eb 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -499,6 +499,7 @@ This example always prints zero. Resources do not leak. [withContext]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html [NonCancellable]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html [withTimeout]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html +[TimeoutCancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-timeout-cancellation-exception/index.html [withTimeoutOrNull]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 25accd0883..83239de20c 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -700,6 +700,7 @@ that should be implemented. [CoroutineScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html [MainScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html [Dispatchers.Main]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html +[CoroutineScope.cancel]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html [asContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html [ensurePresent]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html [ThreadContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt index 195c2ea739..f3027a6ef0 100644 --- a/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt +++ b/kotlinx-coroutines-core/jvm/test/guide/example-cancel-04.kt @@ -9,7 +9,7 @@ fun main() = runBlocking { var nextPrintTime = startTime var i = 0 while (isActive) { // cancellable computation loop - // print a message twice a second + // prints a message twice a second if (currentTimeMillis() >= nextPrintTime) { println("job: I'm sleeping ${i++} ...") nextPrintTime += 500L From 1800912a10038f38e600af3c25454f049675f6cc Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:55:04 +0200 Subject: [PATCH 24/39] docs(cancellation-and-timeouts): Fix inconsistent use of references --- docs/topics/cancellation-and-timeouts.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 89bb70a3eb..0388666733 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -144,7 +144,7 @@ which does not rethrow [CancellationException]. There are two approaches to making computation code cancellable. The first one is periodically invoking a suspending function that checks for cancellation. -There are the [yield] and [ensureActive](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html) +There are the [yield] and [ensureActive] functions, which are great choices for that purpose. The other one is explicitly checking the cancellation status using [isActive]. Let us try the latter approach. @@ -197,7 +197,7 @@ main: Now I can quit. Cancellable suspending functions throw [CancellationException] on cancellation, which can be handled in the usual way. For example, -the `try {...} finally {...}` expression and Kotlin's [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html) +the `try {...} finally {...}` expression and Kotlin's [use] function execute their finalization actions normally when a coroutine is cancelled: ```kotlin From be009596b8cdac1aa17f284ca7dc80f83142acf8 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Tue, 11 Feb 2025 18:59:08 +0200 Subject: [PATCH 25/39] docs(composing-suspending-functions): Reverse the note changes --- docs/topics/composing-suspending-functions.md | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md index 4877d8c12a..1d63cda6a8 100644 --- a/docs/topics/composing-suspending-functions.md +++ b/docs/topics/composing-suspending-functions.md @@ -182,14 +182,13 @@ So, here the two coroutines are defined but not executed as in the previous exam the programmer on when exactly to start the execution by calling [start][Job.start]. We first start `one`, then start `two`, and then await for the individual coroutines to finish. -> Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual -> coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine -> execution and waits for its finish, which is not the intended use-case for laziness. -> The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the -> standard [lazy](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html) function in cases -> when computation of the value involves suspending functions. -> -{style="note"} +Note that if we just call [await][Deferred.await] in `println` without first calling [start][Job.start] on individual +coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine +execution and waits for its finish, which is not the intended use-case for laziness. +The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the +standard [lazy] function in cases +when computation of the value involves suspending functions. + ## Async-style functions From f0988e1347259b1753d453c2b74f594ffae04077 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:24:38 +0200 Subject: [PATCH 26/39] docs(coroutine-context-and-dispatchers): Clarify withContext behavior Expanded the explanation of `withContext` to provide a more precise understanding of its behavior. - Clarified that `withContext` only suspends and switches context if the specified context differs from the current one. - Explained how `CoroutineDispatcher` influences context switching, requiring additional dispatches. - Improved wording for better readability and comprehension. --- .../coroutine-context-and-dispatchers.md | 23 ++++++++----------- 1 file changed, 9 insertions(+), 14 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 83239de20c..7e095da577 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -246,19 +246,19 @@ fun main() { > {style="note"} -The example above demonstrates two important techniques in coroutine usage. +The example above demonstrates new techniques in coroutine usage. The first technique involves using [runBlocking] with an explicitly specified context. This ensures that the coroutine runs in a controlled environment, allowing you to define the execution context explicitly. -The second technique uses the [withContext] function. -When you call [withContext], it suspends the current coroutine and switches to a new context. -This transition may involve changing the dispatcher or updating other context elements. - -After switching, the block of code executes within the newly specified context. -Once it completes, the coroutine automatically reverts to its original context, -ensuring a smooth and controlled execution flow. +When you call [withContext], +it may suspend the current coroutine and switch to a new context +but only if it differs from the current one. +In particular, if you specify a different [CoroutineDispatcher], +additional dispatches are required: +The block is scheduled on the new dispatcher, and once it is completed, +execution returns to the original dispatcher. As a result, the output of the above code is: @@ -270,14 +270,9 @@ As a result, the output of the above code is: -The example above uses the [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html) function from the Kotlin standard library +The example above uses the [use] function from the Kotlin standard library to properly release thread resources created by [newSingleThreadContext] when they're no longer needed. ->Note that [withContext] doesn't create a new coroutine - ->it merely provides a [CoroutineScope] with the specified context. -> -{style="note"} - ## Job in the context The coroutine's [Job] is part of its context, and can be retrieved from it From d74918af506edabdd1b5849133fcedff7dfc772d Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:29:58 +0200 Subject: [PATCH 27/39] docs(coroutine-context-and-dispatchers): Fix the indentation --- docs/topics/coroutine-context-and-dispatchers.md | 1 - 1 file changed, 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 7e095da577..c719981aa4 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -316,7 +316,6 @@ However, this parent-child relation can be explicitly overridden in one of two w 1. When a different scope is explicitly specified when launching a coroutine (for example, `GlobalScope.launch`), it does not inherit a `Job` from the parent scope. - 2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below), it overrides the `Job` of the parent scope. From f10ba778e188e1fb10bcaef045af0057f66dc4fe Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:42:45 +0200 Subject: [PATCH 28/39] docs(coroutine-context-and-dispatchers): Use present tense for ongoing coroutine execution Revised phrasing to reflect that coroutines are continuously launched throughout the application's lifecycle. - Changed "we launched" to "launching" to better align with present continuous tense, emphasizing ongoing behavior. --- docs/topics/coroutine-context-and-dispatchers.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index c719981aa4..5287bd08ea 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -497,8 +497,9 @@ Let us put our knowledge about contexts, children, and jobs together. Assume that our application has an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application, -and we launched various coroutines in the context of an Android activity to perform asynchronous operations to fetch -and update data, do animations, etc. These coroutines must be cancelled when the activity is destroyed +and launching various coroutines in the context of an Android activity +to perform asynchronous operations to fetch and update data, +do animations, etc. These coroutines must be cancelled when the activity is destroyed to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope]. From 865654b960442916c6e600f1a24069aeafe24209 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:46:00 +0200 Subject: [PATCH 29/39] docs(coroutine-context-and-dispatchers): Emphasize that all coroutines get cancelled Added "All" to stress that every coroutine is cancelled, highlighting this crucial aspect of coroutine behavior. --- docs/topics/coroutine-context-and-dispatchers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 5287bd08ea..14f17317f5 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -538,7 +538,7 @@ For the demo, we launch ten coroutines that delay for a different time: ``` In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms. -This cancels the coroutines that were launched from `doSomething`. +This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction of the activity, no more messages are printed, even if we wait a little longer. From 72690d43f64d2c5d08e4698bfa61db44c13c4bdf Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Wed, 12 Feb 2025 21:50:20 +0200 Subject: [PATCH 30/39] docs(coroutine-context-and-dispatchers): Fix grammatical error Corrected "a different threads" to "different threads" for grammatical accuracy. --- docs/topics/coroutine-context-and-dispatchers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 14f17317f5..05286f07f0 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -639,7 +639,7 @@ fun main() = runBlocking { {style="note"} In this example, we launch a new coroutine in a background thread pool using [Dispatchers.Default], so -it works on a different threads from the thread pool, but it still has the value of the thread local variable +it works on different threads from the thread pool, but it still has the value of the thread local variable that we specified using `threadLocal.asContextElement(value = "launch")`, no matter which thread the coroutine is executed on. Thus, the output (with [debug](#debugging-coroutines-and-threads)) is: From 3378775bcec5e214eb4239cbca757b65618ece44 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:19:54 +0200 Subject: [PATCH 31/39] docs(CoroutineScope): Clarify coroutine lifetime emphasis Restored emphasis on "whole application lifetime" to clearly indicate that top-level coroutines span from application start to termination. --- kotlinx-coroutines-core/common/src/CoroutineScope.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt index 68e527cf71..7ae521b1d3 100644 --- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt +++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt @@ -158,8 +158,8 @@ public val CoroutineScope.isActive: Boolean /** * A global [CoroutineScope] not bound to any job. - * Global scope is used to launch top-level coroutines operating on the application lifetime - * and are not cancelled prematurely. + * Global scope is used to launch top-level coroutines that operate + * throughout the application's lifetime and are not canceled prematurely. * * Active coroutines launched in `GlobalScope` do not keep the process alive. They are like daemon threads. * From fbc4e6623f77e5ae62a5ce3112ac79ccd37b8c6f Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:43:23 +0200 Subject: [PATCH 32/39] docs(Job): Restore correct conjunction for coroutine completion conditions Reverted "or" to its original placement to correctly reflect that a job remains active until either the coroutine completes or `CompletableJob.complete` is called. --- kotlinx-coroutines-core/common/src/Job.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt index 451235dd22..524d8eabed 100644 --- a/kotlinx-coroutines-core/common/src/Job.kt +++ b/kotlinx-coroutines-core/common/src/Job.kt @@ -56,7 +56,7 @@ import kotlin.jvm.* * [CoroutineStart.LAZY]. * Such a job can be made _active_ by invoking [start] or [join]. * - * A job is in the _active_ state while the coroutine is working until the [CompletableJob] completes, + * A job is in the _active_ state while the coroutine is working or until the [CompletableJob] completes, * fails, or is cancelled. * * Failure of an _active_ job with an exception transitions the state to the _cancelling_ state. From c8ed37a50088fa20f23bd70c18b88a413b32e6a8 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Thu, 13 Feb 2025 15:46:19 +0200 Subject: [PATCH 33/39] docs(ThreadContextElement): Remove redundant "on" for grammatical accuracy Fixed an extra "on" left over after the change to ensure proper sentence structure and readability. --- kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt index 89a5aa3840..5015a259f0 100644 --- a/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt +++ b/kotlinx-coroutines-core/jvm/src/ThreadContextElement.kt @@ -7,7 +7,7 @@ import kotlin.coroutines.* * Defines elements in a [CoroutineContext] that are installed into the thread context * every time the coroutine with this element in the context is resumed on a thread. * - * Implementations of this interface define a type [S] of the thread-local state that they need to store on + * Implementations of this interface define a type [S] of the thread-local state that they need to store * upon resuming a coroutine and restore later upon suspension. * The infrastructure provides the corresponding storage. * From 14e55260b24f6927dfef62f29991647c4f01f0a7 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Fri, 14 Feb 2025 15:56:40 +0200 Subject: [PATCH 34/39] docs(CoroutineScope): Add a missing article --- kotlinx-coroutines-core/common/src/CoroutineScope.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt index 7ae521b1d3..f5e48655d3 100644 --- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt +++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt @@ -14,7 +14,7 @@ import kotlin.coroutines.intrinsics.* * to automatically propagate all its elements and cancellation. * * The best ways to obtain a standalone instance of the scope are [CoroutineScope()] and [MainScope()] factory functions, - * taking care to cancel these coroutine scopes when they are no longer needed (see section on custom usage below for + * taking care to cancel these coroutine scopes when they are no longer needed (see the section on custom usage below for * explanation and example). * * Additional context elements can be appended to the scope using the [plus][CoroutineScope.plus] operator. From 7aeb177e7db524da2b6c1d4e25bfe2bf5ed016ed Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:03:05 +0200 Subject: [PATCH 35/39] docs: Revert linking to external references --- kotlinx-coroutines-core/common/src/CoroutineScope.kt | 3 +-- kotlinx-coroutines-core/common/src/Job.kt | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/kotlinx-coroutines-core/common/src/CoroutineScope.kt b/kotlinx-coroutines-core/common/src/CoroutineScope.kt index f5e48655d3..076d61dd81 100644 --- a/kotlinx-coroutines-core/common/src/CoroutineScope.kt +++ b/kotlinx-coroutines-core/common/src/CoroutineScope.kt @@ -214,8 +214,7 @@ public val CoroutineScope.isActive: Boolean * * Do not replace `GlobalScope.launch { ... }` with `CoroutineScope().launch { ... }` constructor function call. * The latter has the same pitfalls as `GlobalScope`. See [CoroutineScope] documentation on the intended usage of - * [CoroutineScope()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html) - * constructor function. + * `CoroutineScope()` constructor function. * * ### Legitimate use-cases * diff --git a/kotlinx-coroutines-core/common/src/Job.kt b/kotlinx-coroutines-core/common/src/Job.kt index 524d8eabed..512699e29d 100644 --- a/kotlinx-coroutines-core/common/src/Job.kt +++ b/kotlinx-coroutines-core/common/src/Job.kt @@ -25,8 +25,7 @@ import kotlin.jvm.* * * - A **coroutine job** is created with the [launch][CoroutineScope.launch] coroutine builder. * It runs a specified block of code and completes upon completion of this block. - * - **[CompletableJob]** is created with a [Job()](https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job.html) - * factory function. + * - **[CompletableJob]** is created with a `Job()` factory function. * It is completed by calling [CompletableJob.complete]. * * Conceptually, an execution of a job does not produce a result value. From 69cec210fc13b7acccf3fd187e305378a9fc5d76 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:19:31 +0200 Subject: [PATCH 36/39] docs(coroutine-context-and-dispatchers): Remove vague phrasing and improve clarity Revised the explanation of `runBlocking` to remove the ambiguous phrase "controlled environment" and improve clarity. - Reworded the first technique to focus on specifying a context explicitly. - Refined the explanation of `withContext` to emphasize its behavior when switching contexts. --- docs/topics/coroutine-context-and-dispatchers.md | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 05286f07f0..9d1e688e86 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -248,17 +248,11 @@ fun main() { The example above demonstrates new techniques in coroutine usage. -The first technique involves using [runBlocking] with an explicitly specified context. -This ensures that the coroutine runs in a controlled environment, -allowing you to define the execution context explicitly. - -When you call [withContext], -it may suspend the current coroutine and switch to a new context -but only if it differs from the current one. -In particular, if you specify a different [CoroutineDispatcher], -additional dispatches are required: -The block is scheduled on the new dispatcher, and once it is completed, -execution returns to the original dispatcher. +The first technique shows how to use [runBlocking] with a specified context. +The second technique involves calling [withContext], +which may suspend the current coroutine and switch to a new context—provided the new context differs from the existing one. +Specifically, if you specify a different [CoroutineDispatcher], extra dispatches are required: +the block is scheduled on the new dispatcher, and once it finishes, execution returns to the original dispatcher. As a result, the output of the above code is: From c538102833928d934fc0945722541d19d823a58b Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Fri, 14 Feb 2025 16:29:29 +0200 Subject: [PATCH 37/39] docs(cancellation-and-timeouts): Update the Index using knit --- docs/topics/cancellation-and-timeouts.md | 1 + 1 file changed, 1 insertion(+) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 0388666733..3a14d023b9 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -494,6 +494,7 @@ This example always prints zero. Resources do not leak. [Job.join]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html [CancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html [yield]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html +[ensureActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html [isActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html [CoroutineScope]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html [withContext]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html From 35f545a337783a86a5d3da63a4f3949ecde84baa Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Fri, 14 Feb 2025 17:05:40 +0200 Subject: [PATCH 38/39] docs(coroutine-context-and-dispatchers): Remove the reference to use, since it cannot be identified. --- docs/topics/coroutine-context-and-dispatchers.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/topics/coroutine-context-and-dispatchers.md b/docs/topics/coroutine-context-and-dispatchers.md index 9d1e688e86..ca5f54cd98 100644 --- a/docs/topics/coroutine-context-and-dispatchers.md +++ b/docs/topics/coroutine-context-and-dispatchers.md @@ -264,7 +264,7 @@ As a result, the output of the above code is: -The example above uses the [use] function from the Kotlin standard library +The example above uses the `use` function from the Kotlin standard library to properly release thread resources created by [newSingleThreadContext] when they're no longer needed. ## Job in the context From 4aa22e2d8d7560e85e14de2becbd6170d143fbe9 Mon Sep 17 00:00:00 2001 From: jamhour1g <75880084+jamhour1g@users.noreply.github.com> Date: Thu, 27 Feb 2025 10:53:29 +0200 Subject: [PATCH 39/39] docs: Add explicit links to kotlin's lazy, and use functions --- docs/topics/cancellation-and-timeouts.md | 2 +- docs/topics/composing-suspending-functions.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/topics/cancellation-and-timeouts.md b/docs/topics/cancellation-and-timeouts.md index 3a14d023b9..85190936f1 100644 --- a/docs/topics/cancellation-and-timeouts.md +++ b/docs/topics/cancellation-and-timeouts.md @@ -197,7 +197,7 @@ main: Now I can quit. Cancellable suspending functions throw [CancellationException] on cancellation, which can be handled in the usual way. For example, -the `try {...} finally {...}` expression and Kotlin's [use] +the `try {...} finally {...}` expression and Kotlin's [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html) function execute their finalization actions normally when a coroutine is cancelled: ```kotlin diff --git a/docs/topics/composing-suspending-functions.md b/docs/topics/composing-suspending-functions.md index 1d63cda6a8..1e6f590af2 100644 --- a/docs/topics/composing-suspending-functions.md +++ b/docs/topics/composing-suspending-functions.md @@ -186,7 +186,7 @@ Note that if we just call [await][Deferred.await] in `println` without first cal coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine execution and waits for its finish, which is not the intended use-case for laziness. The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the -standard [lazy] function in cases +standard [lazy](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html) function in cases when computation of the value involves suspending functions.