Skip to content

Flow.kt: fix typos and rephrase some expressions for better readability #1408

New issue

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

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

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 5, 2019
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 28 additions & 28 deletions kotlinx-coroutines-core/common/src/flow/Flow.kt
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import kotlin.coroutines.*
* or [launchIn] operator that starts collection of the flow in the given scope.
* They are applied to the upstream flow and trigger execution of all operations.
* Execution of the flow is also called _collecting the flow_ and is always performed in a suspending manner
* without actual blocking. Terminal operator complete normally or exceptionally depending on successful or failed
* without actual blocking. Terminal operators complete normally or exceptionally depending on successful or failed
* execution of all the flow operations in the upstream. The most basic terminal operator is [collect], for example:
*
* ```
Expand All @@ -37,10 +37,10 @@ import kotlin.coroutines.*
*
* By default, flows are _sequential_ and all flow operations are executed sequentially in the same coroutine,
* with an exception for a few operations specifically designed to introduce concurrency into flow
* the execution such a [buffer] and [flatMapMerge]. See their documentation for details.
* execution such as [buffer] and [flatMapMerge]. See their documentation for details.
*
* Flow interface does not carry information whether a flow is a truly a cold stream that can be collected repeatedly and
* triggers execution of the same code every time it is collected or if it is a hot stream that emits different
* The `Flow` interface does not carry information whether a flow truly is a cold stream that can be collected repeatedly and
* triggers execution of the same code every time it is collected, or if it is a hot stream that emits different
* values from the same running source on each collection. However, conventionally flows represent cold streams.
* Transitions between hot and cold streams are supported via channels and the corresponding API:
* [channelFlow], [produceIn], [broadcastIn].
Expand All @@ -54,27 +54,27 @@ import kotlin.coroutines.*
* * [flow { ... }][flow] builder function to construct arbitrary flows from
* sequential calls to [emit][FlowCollector.emit] function.
* * [channelFlow { ... }][channelFlow] builder function to construct arbitrary flows from
* potentially concurrent calls to [send][kotlinx.coroutines.channels.SendChannel.send] function.
* potentially concurrent calls to the [send][kotlinx.coroutines.channels.SendChannel.send] function.
*
* ### Flow constraints
*
* All implementations of `Flow` interface must adhere to two key properties that are described in detail below:
* All implementations of the `Flow` interface must adhere to two key properties described in detail below:
*
* * Context preservation.
* * Exception transparency.
*
* These properties ensure the ability to perform local reasoning about the code with flows and modularize the code
* in such a way so that upstream flow emitters can be developed separately from downstream flow collectors.
* A user of the flow does not needs to know implementation details of the upstream flows it uses.
* in such a way that upstream flow emitters can be developed separately from downstream flow collectors.
* A user of a flow does not need to be aware of implementation details of the upstream flows it uses.
*
* ### Context preservation
*
* The flow has a context preservation property: it encapsulates its own execution context and never propagates or leaks
* it downstream, thus making reasoning about the execution context of particular transformations or terminal
* operations trivial.
*
* There is the only way to change the context of a flow: [flowOn][Flow.flowOn] operator,
* that changes the upstream context ("everything above the flowOn operator").
* There is only one way to change the context of a flow: the [flowOn][Flow.flowOn] operator
* that changes the upstream context ("everything above the `flowOn` operator").
* For additional information refer to its documentation.
*
* This reasoning can be demonstrated in practice:
Expand All @@ -97,7 +97,7 @@ import kotlin.coroutines.*
* ```
*
* From the implementation point of view, it means that all flow implementations should
* emit only from the same coroutine.
* only emit from the same coroutine.
* This constraint is efficiently enforced by the default [flow] builder.
* The [flow] builder should be used if flow implementation does not start any coroutines.
* Its implementation prevents most of the development mistakes:
Expand All @@ -114,27 +114,27 @@ import kotlin.coroutines.*
* }
* ```
*
* Use [channelFlow] if the collection and emission of the flow are to be separated into multiple coroutines.
* Use [channelFlow] if the collection and emission of a flow are to be separated into multiple coroutines.
* It encapsulates all the context preservation work and allows you to focus on your
* domain-specific problem, rather than invariant implementation details.
* It is possible to use any combination of coroutine builders from within [channelFlow].
*
* If you are looking for the performance and are sure that no concurrent emits and context jumps will happen,
* [flow] builder alongside with [coroutineScope] or [supervisorScope] can be used instead:
* If you are looking for performance and are sure that no concurrent emits and context jumps will happen,
* the [flow] builder can be used alongside a [coroutineScope] or [supervisorScope] instead:
* - Scoped primitive should be used to provide a [CoroutineScope].
* - Changing the context of emission is prohibited, no matter whether it is `withContext(ctx)` or
* builder argument (e.g. `launch(ctx)`).
* a builder argument (e.g. `launch(ctx)`).
* - Collecting another flow from a separate context is allowed, but it has the same effect as
* [flowOn] operator on that flow, which is more efficient.
* applying the [flowOn] operator to that flow, which is more efficient.
*
* ### Exception transparency
*
* Flow implementations never catch or handle exceptions that occur in downstream flows. From the implementation standpoint
* it means that calls to [emit][FlowCollector.emit] and [emitAll] shall never be wrapped into
* `try { ... } catch { ... }` blocks. Exception handling in flows shall be performed with
* [catch][Flow.catch] operator and it is designed to catch only exception coming from upstream flow while passing
* all the downstream exceptions. Similarly, terminal operators like [collect][Flow.collect]
* throw any unhandled exception that occurs in its code or in upstream flows, for example:
* [catch][Flow.catch] operator and it is designed to only catch exceptions coming from upstream flows while passing
* all downstream exceptions. Similarly, terminal operators like [collect][Flow.collect]
* throw any unhandled exceptions that occur in their code or in upstream flows, for example:
*
* ```
* flow { emitData() }
Expand All @@ -143,13 +143,13 @@ import kotlin.coroutines.*
* .map { computeTwo(it) }
* .collect { process(it) } // throws exceptions from process and computeTwo
* ```
* The same reasoning can be applied to [onCompletion] operator that is a declarative replacement for `finally` block.
* The same reasoning can be applied to the [onCompletion] operator that is a declarative replacement for the `finally` block.
*
* Failure to adhere to the exception transparency requirement would result in strange behaviours that would make
* Failure to adhere to the exception transparency requirement can lead to strange behaviors which make
* it hard to reason about the code because an exception in the `collect { ... }` could be somehow "caught"
* by the upstream flow, limiting the ability of local reasoning about the code.
* by an upstream flow, limiting the ability of local reasoning about the code.
*
* Currently, flow infrastructure does not enforce exception transparency contracts, however, it might be enforced
* Currently, the flow infrastructure does not enforce exception transparency contracts, however, it might be enforced
* in the future either at run time or at compile time.
*
* ### Reactive streams
Expand All @@ -162,18 +162,18 @@ public interface Flow<out T> {
* Accepts the given [collector] and [emits][FlowCollector.emit] values into it.
* This method should never be implemented or used directly.
*
* The only way to implement flow interface directly is to extend [AbstractFlow].
* To collect it into the specific collector, either `collector.emitAll(flow)` or `collect { ... }` extension
* should be used. Such limitation ensures that context preservation property is not violated and prevents most
* The only way to implement the `Flow` interface directly is to extend [AbstractFlow].
* To collect it into a specific collector, either `collector.emitAll(flow)` or `collect { ... }` extension
* should be used. Such limitation ensures that the context preservation property is not violated and prevents most
* of the developer mistakes related to concurrency, inconsistent flow dispatchers and cancellation.
*/
@InternalCoroutinesApi
public suspend fun collect(collector: FlowCollector<T>)
}

/**
* Base class to extend to have a stateful implementation of the flow.
* It tracks all the properties required for context preservation and throws [IllegalStateException]
* Base class for stateful implementations of `Flow`.
* It tracks all the properties required for context preservation and throws an [IllegalStateException]
* if any of the properties are violated.
*
* Example of the implementation:
Expand Down