Merge branch 'master' into develop
diff --git a/docs/flow.md b/docs/flow.md
index 43467da..2a3ffb5 100644
--- a/docs/flow.md
+++ b/docs/flow.md
@@ -63,14 +63,14 @@
## Asynchronous Flow
-Suspending functions asynchronously return a single value, but how can you return
-multiple asynchronously computed values? That is what Kotlin Flows are for.
+Suspending functions asynchronously returns a single value, but how can we return
+multiple asynchronously computed values? This is where Kotlin Flows come in.
### Representing multiple values
Multiple values can be represented in Kotlin using [collections].
For example, we can have a function `foo()` that returns a [List]
-of three numbers and print them all using [forEach]:
+of three numbers and then print them all using [forEach]:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -84,7 +84,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-01.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-01.kt).
This code outputs:
@@ -98,8 +98,8 @@
#### Sequences
-If the numbers are computed with some CPU-consuming blocking code
-(each computation taking 100ms) then we can represent the numbers using a [Sequence]:
+If we are computing the numbers with some CPU-consuming blocking code
+(each computation taking 100ms), then we can represent the numbers using a [Sequence]:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -118,7 +118,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-02.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-02.kt).
This code outputs the same numbers, but it waits 100ms before printing each one.
@@ -131,7 +131,7 @@
#### Suspending functions
However, this computation blocks the main thread that is running the code.
-When those values are computed by an asynchronous code we can mark function `foo` with a `suspend` modifier,
+When these values are computed by asynchronous code we can mark the function `foo` with a `suspend` modifier,
so that it can perform its work without blocking and return the result as a list:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -153,7 +153,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-03.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-03.kt).
This code prints the numbers after waiting for a second.
@@ -165,9 +165,8 @@
#### Flows
-Using `List<Int>` result type we can only return all the values at once. To represent
-the stream of values that are being asynchronously computed we can use [`Flow<Int>`][Flow] type similarly
-to the `Sequence<Int>` type for synchronously computed values:
+Using the `List<Int>` result type, means we can only return all the values at once. To represent
+the stream of values that are being asynchronously computed, we can use a [`Flow<Int>`][Flow] type just like we would the `Sequence<Int>` type for synchronously computed values:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -184,7 +183,7 @@
}
fun main() = runBlocking<Unit> {
- // Launch a concurrent coroutine to see that the main thread is not blocked
+ // Launch a concurrent coroutine to check if the main thread is blocked
launch {
for (k in 1..3) {
println("I'm not blocked $k")
@@ -199,7 +198,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt).
This code waits 100ms before printing each number without blocking the main thread. This is verified
by printing "I'm not blocked" every 100ms from a separate coroutine that is running in the main thread:
@@ -215,7 +214,7 @@
<!--- TEST -->
-Notice the following differences of the code with the [Flow] from the earlier examples:
+Notice the following differences in the code with the [Flow] from the earlier examples:
* A builder function for [Flow] type is called [flow].
* Code inside the `flow { ... }` builder block can suspend.
@@ -223,12 +222,12 @@
* Values are _emitted_ from the flow using [emit][FlowCollector.emit] function.
* Values are _collected_ from the flow using [collect][collect] function.
-> You can replace [delay] with `Thread.sleep` in the body of `foo`'s `flow { ... }` and see that the main
+> We can replace [delay] with `Thread.sleep` in the body of `foo`'s `flow { ... }` and see that the main
thread is blocked in this case.
### Flows are cold
-Flows are _cold_ streams similarly to sequences — the code inside a [flow] builder does not
+Flows are _cold_ streams similar to sequences — the code inside a [flow] builder does not
run until the flow is collected. This becomes clear in the following example:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -259,7 +258,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-05.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-05.kt).
Which prints:
@@ -279,17 +278,17 @@
<!--- TEST -->
-That is a key reason why the `foo()` function (which returns a flow) is not marked with `suspend` modifier.
+This is a key reason the `foo()` function (which returns a flow) is not marked with `suspend` modifier.
By itself, `foo()` returns quickly and does not wait for anything. The flow starts every time it is collected,
-that is why we see that when we call `collect` again, we get "Flow started" printed again.
+that is why we see "Flow started" when we call `collect` again.
### Flow cancellation
-Flow adheres to general cooperative cancellation of coroutines. However, flow infrastructure does not introduce
+Flow adheres to the general cooperative cancellation of coroutines. However, flow infrastructure does not introduce
additional cancellation points. It is fully transparent for cancellation. As usual, flow collection can be
-cancelled when the flow is suspended in a cancellable suspending function (like [delay]) and cannot be cancelled otherwise.
+cancelled when the flow is suspended in a cancellable suspending function (like [delay]), and cannot be cancelled otherwise.
-The following example shows how the flow gets cancelled on timeout when running in [withTimeoutOrNull] block
+The following example shows how the flow gets cancelled on a timeout when running in a [withTimeoutOrNull] block
and stops executing its code:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -318,7 +317,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-06.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-06.kt).
Notice how only two numbers get emitted by the flow in `foo()` function, producing the following output:
@@ -335,12 +334,12 @@
### Flow builders
The `flow { ... }` builder from the previous examples is the most basic one. There are other builders for
-convenient declaration of flows:
+easier declaration of flows:
* [flowOf] builder that defines a flow emitting a fixed set of values.
* Various collections and sequences can be converted to flows using `.asFlow()` extension functions.
-Thus, the example that prints numbers from 1 to 3 from a flow can be written as:
+So, the example that prints the numbers from 1 to 3 from a flow can be written as:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -358,7 +357,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-07.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-07.kt).
<!--- TEST
1
@@ -368,17 +367,17 @@
### Intermediate flow operators
-Flows can be transformed with operators similarly to collections and sequences.
+Flows can be transformed with operators, just as you would with collections and sequences.
Intermediate operators are applied to an upstream flow and return a downstream flow.
These operators are cold, just like flows are. A call to such an operator is not
a suspending function itself. It works quickly, returning the definition of a new transformed flow.
The basic operators have familiar names like [map] and [filter].
-The important difference from sequences is that blocks of
-code inside those operators can call suspending functions.
+The important difference to sequences is that blocks of
+code inside these operators can call suspending functions.
For example, a flow of incoming requests can be
-mapped to results with the [map] operator even when performing a request is a long-running
+mapped to the results with the [map] operator, even when performing a request is a long-running
operation that is implemented by a suspending function:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -403,9 +402,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-08.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-08.kt).
-It produces the following three lines, each line appearing after a second:
+It produces the following three lines, each line appearing after each second:
```text
response 1
@@ -418,8 +417,8 @@
#### Transform operator
Among the flow transformation operators, the most general one is called [transform]. It can be used to imitate
-simple transformations like [map] and [filter] as well as implement more complex transformations.
-Using `transform` operator, you can [emit][FlowCollector.emit] arbitrary values an arbitrary number of times.
+simple transformations like [map] and [filter], as well as implement more complex transformations.
+Using the `transform` operator, we can [emit][FlowCollector.emit] arbitrary values an arbitrary number of times.
For example, using `transform` we can emit a string before performing a long-running asynchronous request
and follow it with a response:
@@ -449,7 +448,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-09.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-09.kt).
The output of this code is:
@@ -467,7 +466,7 @@
#### Size-limiting operators
Size-limiting intermediate operators like [take] cancel the execution of the flow when the corresponding limit
-is reached. Cancellation in coroutines is always performed by throwing an exception so that all the resource-management
+is reached. Cancellation in coroutines is always performed by throwing an exception, so that all the resource-management
functions (like `try { ... } finally { ... }` blocks) operate normally in case of cancellation:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -498,10 +497,10 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-10.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-10.kt).
-The output of this code clearly shows that execution of the `flow { ... }` body in `numbers()` function
-had stopped after emitting the second number:
+The output of this code clearly shows that the execution of the `flow { ... }` body in the `numbers()` function
+stopped after emitting the second number:
```text
1
@@ -514,8 +513,7 @@
### Terminal flow operators
Terminal operators on flows are _suspending functions_ that start a collection of the flow.
-The [collect] operator is the most basic one, but there are other terminal operators for
-convenience:
+The [collect] operator is the most basic one, but there are other terminal operators, which can make it easier:
* Conversion to various collections like [toList] and [toSet].
* Operators to get the [first] value and to ensure that a flow emits a [single] value.
@@ -541,7 +539,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-11.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-11.kt).
Prints a single number:
@@ -556,10 +554,10 @@
Each individual collection of a flow is performed sequentially unless special operators that operate
on multiple flows are used. The collection works directly in the coroutine that calls a terminal operator.
No new coroutines are launched by default.
-Each emitted value is processed by all intermediate operators from
-upstream to downstream and is delivered to the terminal operator after that.
+Each emitted value is processed by all the intermediate operators from
+upstream to downstream and is then delivered to the terminal operator after.
-See the following example that filters even integers and maps them to strings:
+See the following example that filters the even integers and maps them to strings:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -586,7 +584,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-12.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-12.kt).
Producing:
@@ -608,7 +606,7 @@
Collection of a flow always happens in the context of the calling coroutine. For example, if there is
a `foo` flow, then the following code runs in the context specified
-by the author of this code, regardless of implementation details of the `foo` flow:
+by the author of this code, regardless of the implementation details of the `foo` flow:
<div class="sample" markdown="1" theme="idea" data-highlight-only>
@@ -654,7 +652,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-13.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-13.kt).
Running this code produces:
@@ -668,14 +666,14 @@
<!--- TEST FLEXIBLE_THREAD -->
Since `foo().collect` is called from the main thread, the body of `foo`'s flow is also called in the main thread.
-This is a perfect default for fast-running or asynchronous code that does not care about the execution context and
+This is the perfect default for fast-running or asynchronous code that does not care about the execution context and
does not block the caller.
#### Wrong emission withContext
However, the long-running CPU-consuming code might need to be executed in the context of [Dispatchers.Default] and UI-updating
code might need to be executed in the context of [Dispatchers.Main]. Usually, [withContext] is used
-to change the context in code using Kotlin coroutines, but code in the `flow { ... }` builder has to honor context
+to change the context in the code using Kotlin coroutines, but code in the `flow { ... }` builder has to honor the context
preservation property and is not allowed to [emit][FlowCollector.emit] from a different context.
Try running the following code:
@@ -688,7 +686,7 @@
//sampleStart
fun foo(): Flow<Int> = flow {
- // WRONG way to change context for CPU-consuming code in flow builder
+ // The WRONG way to change context for CPU-consuming code in flow builder
kotlinx.coroutines.withContext(Dispatchers.Default) {
for (i in 1..3) {
Thread.sleep(100) // pretend we are computing it in CPU-consuming way
@@ -705,7 +703,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt).
This code produces the following exception:
@@ -717,14 +715,14 @@
at ...
-->
-> Note that we had to use a fully qualified name of [kotlinx.coroutines.withContext][withContext] function in this example to
+> Note that we had to use a fully qualified name of the [kotlinx.coroutines.withContext][withContext] function in this example to
demonstrate this exception. A short name of `withContext` would have resolved to a special stub function that
-produces compilation error to prevent us from running into this problem.
+produces a compilation error to prevent us from running into this problem.
#### flowOn operator
-The exception refers to [flowOn] function that shall be used to change the context of flow emission.
-The correct way of changing the context of a flow is shown in the below example, which also prints
+The exception refers to the [flowOn] function that shall be used to change the context of the flow emission.
+The correct way to change the context of a flow is shown in the example below, which also prints the
names of the corresponding threads to show how it all works:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -754,7 +752,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-15.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-15.kt).
Notice how `flow { ... }` works in the background thread, while collection happens in the main thread:
@@ -767,17 +765,17 @@
[main @coroutine#1] Collected 3
-->
-Another observation here is that [flowOn] operator had changed the default sequential nature of the flow.
+Another thing to observe here is that the [flowOn] operator has changed the default sequential nature of the flow.
Now collection happens in one coroutine ("coroutine#1") and emission happens in another coroutine
-("coroutine#2") that is running in another thread concurrently with collecting coroutine. The [flowOn] operator
+("coroutine#2") that is running in another thread concurrently with the collecting coroutine. The [flowOn] operator
creates another coroutine for an upstream flow when it has to change the [CoroutineDispatcher] in its context.
### Buffering
-Running different parts of a flow in different coroutines can be helpful from the standpoint of overall time it takes
+Running different parts of a flow in different coroutines can be helpful from the standpoint of the overall time it takes
to collect the flow, especially when long-running asynchronous operations are involved. For example, consider a case when
-emission by `foo()` flow is slow, taking 100 ms to produce an element; and collector is also slow,
-taking 300 ms to process an element. Let us see how long does it take to collect such a flow with three numbers:
+the emission by `foo()` flow is slow, taking 100 ms to produce an element; and collector is also slow,
+taking 300 ms to process an element. Let's see how long it takes to collect such a flow with three numbers:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -808,9 +806,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-16.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-16.kt).
-It produces something like this, the whole collection taking around 1200 ms (three numbers times 400 ms each):
+It produces something like this, with the whole collection taking around 1200 ms (three numbers, 400 ms for each):
```text
1
@@ -821,7 +819,7 @@
<!--- TEST ARBITRARY_TIME -->
-We can use [buffer] operator on a flow to run emitting code of `foo()` concurrently with collecting code,
+We can use a [buffer] operator on a flow to run emitting code of `foo()` concurrently with collecting code,
as opposed to running them sequentially:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -855,10 +853,10 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-17.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-17.kt).
-It produces the same numbers faster, as we have effectively created a processing pipeline,
-only having to wait 100 ms for the first number and then spending only 300 ms to process
+It produces the same numbers just faster, as we have effectively created a processing pipeline,
+having to only wait 100 ms for the first number and then spending only 300 ms to process
each number. This way it takes around 1000 ms to run:
```text
@@ -870,13 +868,13 @@
<!--- TEST ARBITRARY_TIME -->
-> Note that [flowOn] operator uses the same buffering mechanism when it has to change [CoroutineDispatcher],
-but here we explicitly request buffering without changing execution context.
+> Note that the [flowOn] operator uses the same buffering mechanism when it has to change a [CoroutineDispatcher],
+but here we explicitly request buffering without changing the execution context.
#### Conflation
-When flow represents partial results of some operation or operation status updates, it may not be necessary
-to process each value, but only to process the most recent ones. In this case, [conflate] operator can be used to skip
+When a flow represents partial results of the operation or operation status updates, it may not be necessary
+to process each value, but instead, only most recent ones. In this case, the [conflate] operator can be used to skip
intermediate values when a collector is too slow to process them. Building on the previous example:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -910,9 +908,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-18.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-18.kt).
-We see that while the first number was being processed the second and the third ones were already produced, so
+We see that while the first number was still being processed the second, and third were already produced, so
the second one was _conflated_ and only the most recent (the third one) was delivered to the collector:
```text
@@ -925,10 +923,10 @@
#### Processing the latest value
-Conflation is one way to speed up processing when both emitter and collector are slow. It does that by dropping emitted values.
-The other way is to cancel slow collector and restart it every time a new value is emitted. There is
-a family of `xxxLatest` operators that perform the same essential logic of `xxx` operator, but cancel the
-code in their block on a new value. Let us change the previous example from [conflate] to [collectLatest]:
+Conflation is one way to speed up processing when both the emitter and collector are slow. It does it by dropping emitted values.
+The other way is to cancel a slow collector and restart it every time a new value is emitted. There is
+a family of `xxxLatest` operators that perform the same essential logic of a `xxx` operator, but cancel the
+code in their block on a new value. Let's try changing [conflate] to [collectLatest] in the previous example:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -961,7 +959,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-19.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-19.kt).
Since the body of [collectLatest] takes 300 ms, but new values are emitted every 100 ms, we see that the block
is run on every value, but completes only for the last value:
@@ -978,12 +976,12 @@
### Composing multiple flows
-There are several ways to compose multiple flows.
+There are lots of ways to compose multiple flows.
#### Zip
-Similarly to [Sequence.zip] extension function in the Kotlin standard library,
-flows have [zip] operator that combines the corresponding values of two flows:
+Just like the [Sequence.zip] extension function in the Kotlin standard library,
+flows have a [zip] operator that combines the corresponding values of two flows:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1003,7 +1001,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-20.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-20.kt).
This example prints:
@@ -1017,16 +1015,16 @@
#### Combine
-When flow represents the most recent value of some variable or operation (see also a related
-section on [conflation](#conflation)) it might be needed to perform a computation that depends on
-the most recent values of the corresponding flows and to recompute it whenever any of upstream
+When flow represents the most recent value of a variable or operation (see also the related
+section on [conflation](#conflation)), it might be needed to perform a computation that depends on
+the most recent values of the corresponding flows and to recompute it whenever any of the upstream
flows emit a value. The corresponding family of operators is called [combine].
For example, if the numbers in the previous example update every 300ms, but strings update every 400 ms,
-then zipping them using [zip] operator would still produce the same result,
-albeit results are going to be printed every 400 ms:
+then zipping them using the [zip] operator will still produce the same result,
+albeit results that are printed every 400 ms:
-> We use [onEach] intermediate operator in this example to delay each element and thus make the code
+> We use a [onEach] intermediate operator in this example to delay each element and make the code
that emits sample flows more declarative and shorter.
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1050,7 +1048,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-21.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-21.kt).
<!--- TEST ARBITRARY_TIME
1 -> one at 437 ms from start
@@ -1058,7 +1056,7 @@
3 -> three at 1243 ms from start
-->
-However, using [combine] operator here instead of [zip]:
+However, when using a [combine] operator here instead of a [zip]:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1081,7 +1079,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-22.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-22.kt).
We get quite a different output, where a line is printed at each emission from either `nums` or `strs` flows:
@@ -1129,13 +1127,13 @@
Then we end up with a flow of flows (`Flow<Flow<String>>`) that needs to be _flattened_ into a single flow for
further processing. Collections and sequences have [flatten][Sequence.flatten] and [flatMap][Sequence.flatMap]
-operators for this purpose. However, the asynchronous nature of flows calls for different _modes_ of flattening
-thus there is a family of flattening operators on flows.
+operators for this. However, due the asynchronous nature of flows they call for different _modes_ of flattening,
+as such, there is a family of flattening operators on flows.
#### flatMapConcat
Concatenating mode is implemented by [flatMapConcat] and [flattenConcat] operators. They are the most direct
-analogues of the corresponding sequence operators. They wait for inner flow to complete before
+analogues of the corresponding sequence operators. They wait for the inner flow to complete before
starting to collect the next one as the following example shows:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1164,7 +1162,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-23.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-23.kt).
The sequential nature of [flatMapConcat] is clearly seen in the output:
@@ -1213,7 +1211,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-24.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-24.kt).
The concurrent nature of [flatMapMerge] is obvious:
@@ -1228,16 +1226,16 @@
<!--- TEST ARBITRARY_TIME -->
-> Note that [flatMapMerge] call its block of code (`{ requestFlow(it) }` in this example) sequentially, but
-collects the resulting flows concurrently, so it is equivalent to performing a sequential
+> Note that the [flatMapMerge] calls its block of code (`{ requestFlow(it) }` in this example) sequentially, but
+collects the resulting flows concurrently, it is the equivalent of performing a sequential
`map { requestFlow(it) }` first and then calling [flattenMerge] on the result.
#### flatMapLatest
-In a similar way to [collectLatest] operator that was shown in
+In a similar way to the [collectLatest] operator, that was shown in
["Processing the latest value"](#processing-the-latest-value) section, there is the corresponding "Latest"
-flattening mode where collection of the previous flow is cancelled as soon as new flow is emitted.
-It is implemented by [flatMapLatest] operator.
+flattening mode where a collection of the previous flow is cancelled as soon as new flow is emitted.
+It is implemented by the [flatMapLatest] operator.
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1265,9 +1263,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-25.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-25.kt).
-The output of this example speaks for the way [flatMapLatest] works:
+The output here in this example is a good demonstration of how [flatMapLatest] works:
```text
1: First at 142 ms from start
@@ -1284,7 +1282,7 @@
### Flow exceptions
-Flow collection can complete with an exception when emitter or any code inside any of the operators throw an exception.
+Flow collection can complete with an exception when an emitter or code inside the operators throw an exception.
There are several ways to handle these exceptions.
#### Collector try and catch
@@ -1320,10 +1318,10 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-26.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-26.kt).
This code successfully catches an exception in [collect] terminal operator and,
-as you can see, no more values are emitted after that:
+as we see, no more values are emitted after that:
```text
Emitting 1
@@ -1337,8 +1335,8 @@
#### Everything is caught
-The previous example actually catches any exception happening in emitter or in any intermediate or terminal operators.
-For example, let us change the code so that emitted values are [mapped][map] to strings,
+The previous example actually catches any exception happening in the emitter or in any intermediate or terminal operators.
+For example, let's change the code so that emitted values are [mapped][map] to strings,
but the corresponding code produces an exception:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1372,7 +1370,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-27.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-27.kt).
This exception is still caught and collection is stopped:
@@ -1387,13 +1385,13 @@
### Exception transparency
-But how can code of emitter encapsulate its exception handling behavior?
+But how can code of the emitter encapsulate its exception handling behavior?
-Flows must be _transparent to exceptions_ and it is a violation of exception transparency to [emit][FlowCollector.emit] values in the
-`flow { ... }` builder from inside of `try/catch` block. This guarantees that a collector throwing an exception
+Flows must be _transparent to exceptions_ and it is a violation of the exception transparency to [emit][FlowCollector.emit] values in the
+`flow { ... }` builder from inside of a `try/catch` block. This guarantees that a collector throwing an exception
can always catch it using `try/catch` as in the previous example.
-The emitter can use [catch] operator that preserves this exception transparency and allows encapsulation
+The emitter can use a [catch] operator that preserves this exception transparency and allows encapsulation
of its exception handling. The body of the `catch` operator can analyze an exception
and react to it in different ways depending on which exception was caught:
@@ -1401,7 +1399,7 @@
* Exceptions can be turned into emission of values using [emit][FlowCollector.emit] from the body of [catch].
* Exceptions can be ignored, logged, or processed by some other code.
-For example, let us emit a text on catching an exception:
+For example, let us emit the text on catching an exception:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1432,7 +1430,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-28.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-28.kt).
The output of the example is the same, even though we do not have `try/catch` around the code anymore.
@@ -1476,9 +1474,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-29.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-29.kt).
-The "Caught ..." message is not printed despite the `catch` operator:
+A "Caught ..." message is not printed despite there being a `catch` operator:
<!--- TEST EXCEPTION
Emitting 1
@@ -1490,8 +1488,8 @@
#### Catching declaratively
-We can combine a declarative nature of [catch] operator with a desire to handle all exceptions by moving the body
-of [collect] operator into [onEach] and putting it before the `catch` operator. Collection of this flow must
+We can combine the declarative nature of the [catch] operator with a desire to handle all the exceptions, by moving the body
+of the [collect] operator into [onEach] and putting it before the `catch` operator. Collection of this flow must
be triggered by a call to `collect()` without parameters:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1522,9 +1520,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-30.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-30.kt).
-Now we can see that "Caught ..." message is printed and thus we can catch all exceptions without explicitly
+Now we can see that a "Caught ..." message is printed and so we can catch all the exceptions without explicitly
using a `try/catch` block:
<!--- TEST EXCEPTION
@@ -1536,12 +1534,12 @@
### Flow completion
-When flow collection completes (normally or exceptionally) it may be needed to execute some action.
-As you might have already noticed, it also can be done in two ways: imperative and declarative.
+When flow collection completes (normally or exceptionally) it may need to execute an action.
+As you may have already noticed, it can be done in two ways: imperative or declarative.
#### Imperative finally block
-In addition to `try`/`catch`, a collector can also use `finally` block to execute an action
+In addition to `try`/`catch`, a collector can also use a `finally` block to execute an action
upon `collect` completion.
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1565,9 +1563,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-31.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-31.kt).
-This code prints three numbers produced by the `foo()` flow followed by "Done" string:
+This code prints three numbers produced by the `foo()` flow followed by a "Done" string:
```text
1
@@ -1580,10 +1578,10 @@
#### Declarative handling
-For declarative approach, flow has [onCompletion] intermediate operator that is invoked
-when the flow is completely collected.
+For the declarative approach, flow has [onCompletion] intermediate operator that is invoked
+when the flow has completely collected.
-The previous example can be rewritten using [onCompletion] operator and produces the same output:
+The previous example can be rewritten using an [onCompletion] operator and produces the same output:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1603,7 +1601,7 @@
```
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-32.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-32.kt).
<!--- TEST
1
@@ -1613,8 +1611,8 @@
-->
The key advantage of [onCompletion] is a nullable `Throwable` parameter of the lambda that can be used
-to determine whether flow collection was completed normally or exceptionally. In the following
-example `foo()` flow throws exception after emitting number 1:
+to determine whether the flow collection was completed normally or exceptionally. In the following
+example the `foo()` flow throws an exception after emitting the number 1:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1638,7 +1636,7 @@
```
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-33.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-33.kt).
As you may expect, it prints:
@@ -1650,13 +1648,13 @@
<!--- TEST -->
-[onCompletion] operator, unlike [catch], does not handle the exception. As we can see from the above
+The [onCompletion] operator, unlike [catch], does not handle the exception. As we can see from the above
example code, the exception still flows downstream. It will be delivered to further `onCompletion` operators
-and can be handled with `catch` operator.
+and can be handled with a `catch` operator.
#### Upstream exceptions only
-Just like [catch] operator, [onCompletion] sees only exception coming from upstream and does not
+Just like the [catch] operator, [onCompletion] only sees exceptions coming from upstream and does not
see downstream exceptions. For example, run the following code:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1681,9 +1679,9 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-34.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-34.kt).
-And you can see the completion cause is null, yet collection failed with exception:
+We can see the completion cause is null, yet collection failed with exception:
```text
1
@@ -1695,20 +1693,20 @@
### Imperative versus declarative
-Now we know how to collect flow, handle its completion and exceptions in both imperative and declarative ways.
-The natural question here is which approach should be preferred and why.
+Now we know how to collect flow, and handle its completion and exceptions in both imperative and declarative ways.
+The natural question here is, which approach is preferred and why?
As a library, we do not advocate for any particular approach and believe that both options
are valid and should be selected according to your own preferences and code style.
### Launching flow
-It is convenient to use flows to represent asynchronous events that are coming from some source.
-In this case, we need an analogue of `addEventListener` function that registers a piece of code with a reaction
-on incoming events and continues further work. The [onEach] operator can serve this role.
+It is easy to use flows to represent asynchronous events that are coming from some source.
+In this case, we need an analogue of the `addEventListener` function that registers a piece of code with a reaction
+for incoming events and continues further work. The [onEach] operator can serve this role.
However, `onEach` is an intermediate operator. We also need a terminal operator to collect the flow.
Otherwise, just calling `onEach` has no effect.
-If we use [collect] terminal operator after `onEach`, then code after it waits until the flow is collected:
+If we use the [collect] terminal operator after `onEach`, then the code after it will wait until the flow is collected:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1731,7 +1729,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-35.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-35.kt).
As you can see, it prints:
@@ -1744,8 +1742,8 @@
<!--- TEST -->
-Here [launchIn] terminal operator comes in handy. Replacing `collect` with `launchIn` we can
-launch collection of the flow in a separate coroutine, so that execution of further code
+The [launchIn] terminal operator comes in handy here. By replacing `collect` with `launchIn` we can
+launch a collection of the flow in a separate coroutine, so that execution of further code
immediately continues:
<div class="sample" markdown="1" theme="idea" data-min-compiler-version="1.3">
@@ -1769,7 +1767,7 @@
</div>
-> You can get full code [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-36.kt).
+> You can get the full code from [here](../kotlinx-coroutines-core/jvm/test/guide/example-flow-36.kt).
It prints:
@@ -1783,17 +1781,17 @@
<!--- TEST -->
The required parameter to `launchIn` must specify a [CoroutineScope] in which the coroutine to collect the flow is
-launched. In the above example this scope comes from [runBlocking]
-coroutine builder, so while the flow is running this [runBlocking] scope waits for completion of its child coroutine
+launched. In the above example this scope comes from the [runBlocking]
+coroutine builder, so while the flow is running, this [runBlocking] scope waits for completion of its child coroutine
and keeps the main function from returning and terminating this example.
-In real applications a scope is going to come from some entity with a limited
+In actual applications a scope will come from an entity with a limited
lifetime. As soon as the lifetime of this entity is terminated the corresponding scope is cancelled, cancelling
-collection of the corresponding flow. This way the pair of `onEach { ... }.launchIn(scope)` works
-like `addEventListener`. However, there is no need for the corresponding `removeEventListener` function,
+the collection of the corresponding flow. This way the pair of `onEach { ... }.launchIn(scope)` works
+like the `addEventListener`. However, there is no need for the corresponding `removeEventListener` function,
as cancellation and structured concurrency serve this purpose.
-Note, that [launchIn] also returns a [Job] which can be used to [cancel][Job.cancel] the corresponding flow collection
+Note that [launchIn] also returns a [Job], which can be used to [cancel][Job.cancel] the corresponding flow collection
coroutine only without cancelling the whole scope or to [join][Job.join] it.
<!-- stdlib references -->
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt b/kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt
index 9a3c05c..7bde16c 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-flow-04.kt
@@ -16,7 +16,7 @@
}
fun main() = runBlocking<Unit> {
- // Launch a concurrent coroutine to see that the main thread is not blocked
+ // Launch a concurrent coroutine to check if the main thread is blocked
launch {
for (k in 1..3) {
println("I'm not blocked $k")
diff --git a/kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt b/kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt
index 6996abc..6628d12 100644
--- a/kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt
+++ b/kotlinx-coroutines-core/jvm/test/guide/example-flow-14.kt
@@ -9,7 +9,7 @@
import kotlinx.coroutines.flow.*
fun foo(): Flow<Int> = flow {
- // WRONG way to change context for CPU-consuming code in flow builder
+ // The WRONG way to change context for CPU-consuming code in flow builder
kotlinx.coroutines.withContext(Dispatchers.Default) {
for (i in 1..3) {
Thread.sleep(100) // pretend we are computing it in CPU-consuming way