Skip to content

Commit c08fa74

Browse files
authored
Minor Improvements to the documentation and code comments (#4346)
Refined the wording for better readability and correctness. Added missing articles and restructured sentences to avoid splitting the infinitive.
1 parent 56646ae commit c08fa74

11 files changed

+137
-96
lines changed

docs/topics/cancellation-and-timeouts.md

+17-10
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,8 @@ This section covers coroutine cancellation and timeouts.
77

88
## Cancelling coroutine execution
99

10-
In a long-running application you might need fine-grained control on your background coroutines.
11-
For example, a user might have closed the page that launched a coroutine and now its result
10+
In a long-running application, you might need fine-grained control on your background coroutines.
11+
For example, a user might have closed the page that launched a coroutine, and now its result
1212
is no longer needed and its operation can be cancelled.
1313
The [launch] function returns a [Job] that can be used to cancel the running coroutine:
1414

@@ -142,9 +142,12 @@ which does not rethrow [CancellationException].
142142

143143
## Making computation code cancellable
144144

145-
There are two approaches to making computation code cancellable. The first one is to periodically
146-
invoke a suspending function that checks for cancellation. There is a [yield] function that is a good choice for that purpose.
147-
The other one is to explicitly check the cancellation status. Let us try the latter approach.
145+
There are two approaches to making computation code cancellable.
146+
The first one is periodically invoking a suspending function that checks for cancellation.
147+
There are the [yield] and [ensureActive]
148+
functions, which are great choices for that purpose.
149+
The other one is explicitly checking the cancellation status using [isActive].
150+
Let us try the latter approach.
148151

149152
Replace `while (i < 5)` in the previous example with `while (isActive)` and rerun it.
150153

@@ -158,7 +161,7 @@ fun main() = runBlocking {
158161
var nextPrintTime = startTime
159162
var i = 0
160163
while (isActive) { // cancellable computation loop
161-
// print a message twice a second
164+
// prints a message twice a second
162165
if (System.currentTimeMillis() >= nextPrintTime) {
163166
println("job: I'm sleeping ${i++} ...")
164167
nextPrintTime += 500L
@@ -192,8 +195,10 @@ main: Now I can quit.
192195
## Closing resources with finally
193196

194197
Cancellable suspending functions throw [CancellationException] on cancellation, which can be handled in
195-
the usual way. For example, the `try {...} finally {...}` expression and Kotlin's `use` function execute their
196-
finalization actions normally when a coroutine is cancelled:
198+
the usual way.
199+
For example,
200+
the `try {...} finally {...}` expression and Kotlin's [use](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.io/use.html)
201+
function execute their finalization actions normally when a coroutine is cancelled:
197202

198203
```kotlin
199204
import kotlinx.coroutines.*
@@ -241,7 +246,7 @@ main: Now I can quit.
241246

242247
Any attempt to use a suspending function in the `finally` block of the previous example causes
243248
[CancellationException], because the coroutine running this code is cancelled. Usually, this is not a
244-
problem, since all well-behaving closing operations (closing a file, cancelling a job, or closing any kind of a
249+
problem, since all well-behaved closing operations (closing a file, cancelling a job, or closing any kind of
245250
communication channel) are usually non-blocking and do not involve any suspending functions. However, in the
246251
rare case when you need to suspend in a cancelled coroutine you can wrap the corresponding code in
247252
`withContext(NonCancellable) {...}` using [withContext] function and [NonCancellable] context as the following example shows:
@@ -327,7 +332,7 @@ Exception in thread "main" kotlinx.coroutines.TimeoutCancellationException: Time
327332

328333
<!--- TEST STARTS_WITH -->
329334

330-
The `TimeoutCancellationException` that is thrown by [withTimeout] is a subclass of [CancellationException].
335+
The [TimeoutCancellationException] that is thrown by [withTimeout] is a subclass of [CancellationException].
331336
We have not seen its stack trace printed on the console before. That is because
332337
inside a cancelled coroutine `CancellationException` is considered to be a normal reason for coroutine completion.
333338
However, in this example we have used `withTimeout` right inside the `main` function.
@@ -489,11 +494,13 @@ This example always prints zero. Resources do not leak.
489494
[Job.join]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-job/join.html
490495
[CancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-cancellation-exception/index.html
491496
[yield]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/yield.html
497+
[ensureActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-active.html
492498
[isActive]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/is-active.html
493499
[CoroutineScope]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope/index.html
494500
[withContext]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-context.html
495501
[NonCancellable]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-non-cancellable/index.html
496502
[withTimeout]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout.html
503+
[TimeoutCancellationException]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-timeout-cancellation-exception/index.html
497504
[withTimeoutOrNull]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/with-timeout-or-null.html
498505

499506
<!--- END -->

docs/topics/composing-suspending-functions.md

+7-5
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,9 @@ Note that if we just call [await][Deferred.await] in `println` without first cal
186186
coroutines, this will lead to sequential behavior, since [await][Deferred.await] starts the coroutine
187187
execution and waits for its finish, which is not the intended use-case for laziness.
188188
The use-case for `async(start = CoroutineStart.LAZY)` is a replacement for the
189-
standard `lazy` function in cases when computation of the value involves suspending functions.
189+
standard [lazy](https://kotlinlang.org/api/core/kotlin-stdlib/kotlin/lazy.html) function in cases
190+
when computation of the value involves suspending functions.
191+
190192

191193
## Async-style functions
192194

@@ -291,10 +293,10 @@ concurrency, as shown in the section below.
291293

292294
## Structured concurrency with async
293295

294-
Let us take the [Concurrent using async](#concurrent-using-async) example and extract a function that
295-
concurrently performs `doSomethingUsefulOne` and `doSomethingUsefulTwo` and returns the sum of their results.
296-
Because the [async] coroutine builder is defined as an extension on [CoroutineScope], we need to have it in the
297-
scope and that is what the [coroutineScope][_coroutineScope] function provides:
296+
Let's refactor the [Concurrent using async](#concurrent-using-async) example into a function that runs
297+
`doSomethingUsefulOne` and `doSomethingUsefulTwo` concurrently and returns their combined results.
298+
Since [async] is a [CoroutineScope] extension,
299+
we'll use the [coroutineScope][_coroutineScope] function to provide the necessary scope:
298300

299301
```kotlin
300302
suspend fun concurrentSum(): Int = coroutineScope {

docs/topics/coroutine-context-and-dispatchers.md

+41-27
Original file line numberDiff line numberDiff line change
@@ -246,9 +246,15 @@ fun main() {
246246
>
247247
{style="note"}
248248

249-
It demonstrates several new techniques. One is using [runBlocking] with an explicitly specified context, and
250-
the other one is using the [withContext] function to change the context of a coroutine while still staying in the
251-
same coroutine, as you can see in the output below:
249+
The example above demonstrates new techniques in coroutine usage.
250+
251+
The first technique shows how to use [runBlocking] with a specified context.
252+
The second technique involves calling [withContext],
253+
which may suspend the current coroutine and switch to a new context—provided the new context differs from the existing one.
254+
Specifically, if you specify a different [CoroutineDispatcher], extra dispatches are required:
255+
the block is scheduled on the new dispatcher, and once it finishes, execution returns to the original dispatcher.
256+
257+
As a result, the output of the above code is:
252258

253259
```text
254260
[Ctx1 @coroutine#1] Started in ctx1
@@ -258,8 +264,8 @@ same coroutine, as you can see in the output below:
258264

259265
<!--- TEST -->
260266

261-
Note that this example also uses the `use` function from the Kotlin standard library to release threads
262-
created with [newSingleThreadContext] when they are no longer needed.
267+
The example above uses the `use` function from the Kotlin standard library
268+
to properly release thread resources created by [newSingleThreadContext] when they're no longer needed.
263269

264270
## Job in the context
265271

@@ -281,7 +287,7 @@ fun main() = runBlocking<Unit> {
281287
>
282288
{style="note"}
283289

284-
In the [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
290+
In [debug mode](#debugging-coroutines-and-threads), it outputs something like this:
285291

286292
```
287293
My job is "coroutine#1":BlockingCoroutine{Active}@6d311334
@@ -300,12 +306,12 @@ the [Job] of the new coroutine becomes
300306
a _child_ of the parent coroutine's job. When the parent coroutine is cancelled, all its children
301307
are recursively cancelled, too.
302308

303-
However, this parent-child relation can be explicitly overriden in one of two ways:
309+
However, this parent-child relation can be explicitly overridden in one of two ways:
304310

305311
1. When a different scope is explicitly specified when launching a coroutine (for example, `GlobalScope.launch`),
306-
then it does not inherit a `Job` from the parent scope.
307-
2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below),
308-
then it overrides the `Job` of the parent scope.
312+
it does not inherit a `Job` from the parent scope.
313+
2. When a different `Job` object is passed as the context for the new coroutine (as shown in the example below),
314+
it overrides the `Job` of the parent scope.
309315

310316
In both cases, the launched coroutine is not tied to the scope it was launched from and operates independently.
311317

@@ -356,7 +362,8 @@ job1: I am not affected by cancellation of the request
356362

357363
## Parental responsibilities
358364

359-
A parent coroutine always waits for completion of all its children. A parent does not have to explicitly track
365+
A parent coroutine always waits for the completion of all its children.
366+
A parent does not have to explicitly track
360367
all the children it launches, and it does not have to use [Job.join] to wait for them at the end:
361368

362369
```kotlin
@@ -480,11 +487,15 @@ I'm working in thread DefaultDispatcher-worker-1 @test#2
480487

481488
## Coroutine scope
482489

483-
Let us put our knowledge about contexts, children and jobs together. Assume that our application has
484-
an object with a lifecycle, but that object is not a coroutine. For example, we are writing an Android application
485-
and launch various coroutines in the context of an Android activity to perform asynchronous operations to fetch
486-
and update data, do animations, etc. All of these coroutines must be cancelled when the activity is destroyed
487-
to avoid memory leaks. We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
490+
Let us put our knowledge about contexts, children, and jobs together.
491+
Assume that our application has an object with a lifecycle, but that object is not a coroutine.
492+
For example,
493+
we are writing an Android application,
494+
and launching various coroutines in the context of an Android activity
495+
to perform asynchronous operations to fetch and update data,
496+
do animations, etc. These coroutines must be cancelled when the activity is destroyed
497+
to avoid memory leaks.
498+
We, of course, can manipulate contexts and jobs manually to tie the lifecycles of the activity
488499
and its coroutines, but `kotlinx.coroutines` provides an abstraction encapsulating that: [CoroutineScope].
489500
You should be already familiar with the coroutine scope as all coroutine builders are declared as extensions on it.
490501

@@ -521,8 +532,9 @@ For the demo, we launch ten coroutines that delay for a different time:
521532
```
522533

523534
In our main function we create the activity, call our test `doSomething` function, and destroy the activity after 500ms.
524-
This cancels all the coroutines that were launched from `doSomething`. We can see that because after the destruction
525-
of the activity no more messages are printed, even if we wait a little longer.
535+
This cancels all the coroutines that were launched from `doSomething`.
536+
We can see that because after the destruction
537+
of the activity, no more messages are printed, even if we wait a little longer.
526538

527539
<!--- CLEAR -->
528540

@@ -577,16 +589,16 @@ Destroying activity!
577589
<!--- TEST -->
578590

579591
As you can see, only the first two coroutines print a message and the others are cancelled
580-
by a single invocation of `job.cancel()` in `Activity.destroy()`.
592+
by a single invocation of [`mainScope.cancel()`][CoroutineScope.cancel] in `Activity.destroy()`.
581593

582-
> Note, that Android has first-party support for coroutine scope in all entities with the lifecycle.
594+
> Note that Android has first-party support for coroutine scope in all entities with the lifecycle.
583595
> See [the corresponding documentation](https://developer.android.com/topic/libraries/architecture/coroutines#lifecyclescope).
584596
>
585597
{style="note"}
586598

587599
### Thread-local data
588600

589-
Sometimes it is convenient to have an ability to pass some thread-local data to or between coroutines.
601+
Sometimes it is convenient to be able to pass some thread-local data to or between coroutines.
590602
However, since they are not bound to any particular thread, this will likely lead to boilerplate if done manually.
591603

592604
For [`ThreadLocal`](https://docs.oracle.com/javase/8/docs/api/java/lang/ThreadLocal.html),
@@ -620,8 +632,8 @@ fun main() = runBlocking<Unit> {
620632
>
621633
{style="note"}
622634

623-
In this example we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
624-
it works on a different thread from the thread pool, but it still has the value of the thread local variable
635+
In this example, we launch a new coroutine in a background thread pool using [Dispatchers.Default], so
636+
it works on different threads from the thread pool, but it still has the value of the thread local variable
625637
that we specified using `threadLocal.asContextElement(value = "launch")`,
626638
no matter which thread the coroutine is executed on.
627639
Thus, the output (with [debug](#debugging-coroutines-and-threads)) is:
@@ -636,7 +648,7 @@ Post-main, current thread: Thread[main @coroutine#1,5,main], thread local value:
636648
<!--- TEST FLEXIBLE_THREAD -->
637649

638650
It's easy to forget to set the corresponding context element. The thread-local variable accessed from the coroutine may
639-
then have an unexpected value, if the thread running the coroutine is different.
651+
then have an unexpected value if the thread running the coroutine is different.
640652
To avoid such situations, it is recommended to use the [ensurePresent] method
641653
and fail-fast on improper usages.
642654

@@ -646,11 +658,12 @@ It has one key limitation, though: when a thread-local is mutated, a new value i
646658
Use [withContext] to update the value of the thread-local in a coroutine, see [asContextElement] for more details.
647659

648660
Alternatively, a value can be stored in a mutable box like `class Counter(var i: Int)`, which is, in turn,
649-
stored in a thread-local variable. However, in this case you are fully responsible to synchronize
661+
stored in a thread-local variable.
662+
However, in this case, you are fully responsible to synchronize
650663
potentially concurrent modifications to the variable in this mutable box.
651664

652-
For advanced usage, for example for integration with logging MDC, transactional contexts or any other libraries
653-
which internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
665+
For advanced usage, for example, for integration with logging MDC, transactional contexts or any other libraries
666+
that internally use thread-locals for passing data, see the documentation of the [ThreadContextElement] interface
654667
that should be implemented.
655668

656669
<!--- MODULE kotlinx-coroutines-core -->
@@ -676,6 +689,7 @@ that should be implemented.
676689
[CoroutineScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-coroutine-scope.html
677690
[MainScope()]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-main-scope.html
678691
[Dispatchers.Main]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-dispatchers/-main.html
692+
[CoroutineScope.cancel]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/cancel.html
679693
[asContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/as-context-element.html
680694
[ensurePresent]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/ensure-present.html
681695
[ThreadContextElement]: https://kotlinlang.org/api/kotlinx.coroutines/kotlinx-coroutines-core/kotlinx.coroutines/-thread-context-element/index.html

docs/topics/coroutines-basics.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -212,8 +212,8 @@ Done
212212
## An explicit job
213213

214214
A [launch] coroutine builder returns a [Job] object that is a handle to the launched coroutine and can be
215-
used to explicitly wait for its completion. For example, you can wait for completion of the child coroutine
216-
and then print "Done" string:
215+
used to wait for its completion explicitly.
216+
For example, you can wait for the completion of the child coroutine and then print the "Done" string:
217217

218218
```kotlin
219219
import kotlinx.coroutines.*

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

+5-4
Original file line numberDiff line numberDiff line change
@@ -32,12 +32,13 @@ public interface CompletableJob : Job {
3232
*
3333
* Subsequent invocations of this function have no effect and always produce `false`.
3434
*
35-
* This function transitions this job into _cancelled_ state if it was not completed or cancelled yet.
36-
* However, that if this job has children, then it transitions into _cancelling_ state and becomes _cancelled_
35+
* This function transitions this job into the _cancelled_ state if it has not been _completed_ or _cancelled_ yet.
36+
* However, if this job has children, then it transitions into the _cancelling_ state and becomes _cancelled_
3737
* once all its children are [complete][isCompleted]. See [Job] for details.
3838
*
39-
* Its responsibility of the caller to properly handle and report the given [exception], all job's children will receive
40-
* a [CancellationException] with the [exception] as a cause for the sake of diagnostic.
39+
* It is the responsibility of the caller to properly handle and report the given [exception].
40+
* All the job’s children will receive a [CancellationException] with
41+
* the [exception] as a cause for the sake of diagnosis.
4142
*/
4243
public fun completeExceptionally(exception: Throwable): Boolean
4344
}

0 commit comments

Comments
 (0)