Repository: tokio-rs/tokio
File: tokio/src/macros/select.rs (Rust)

Code before:
        ///
        /// To determine whether your own methods are cancellation safe, look for the
        /// location of uses of `.await`. This is because when an asynchronous method is
        /// cancelled, that always happens at an `.await`. If your function behaves
        /// correctly even if it is restarted while waiting at an `.await`, then it is
        /// cancellation safe.
        ///
        /// Cancellation safety can be defined in the following way: If you have a
        /// future that has not yet completed, then it must be a no-op to drop that
        /// future and recreate it. This definition is motivated by the situation where
        /// a `select!` is used in a loop. Without this guarantee, you would lose your
        /// progress when another branch completes and you restart the `select!` by
        /// going around the loop.
        ///
        /// Be aware that cancelling something that is not cancellation safe is not
        /// necessarily wrong. For example, if you are cancelling a task because the
        /// application is shutting down, then you probably don't care that partially
        /// read data is lost.
        ///
        /// # Alternatives from the Ecosystem
        ///
        /// The `select!` macro is a versatile tool for working with multiple asynchronous
        /// branches, allowing tasks to run concurrently within the same thread. However,
        /// depending on your use case, ecosystem alternatives can provide additional
        /// benefits, such as more straightforward syntax, more transparent control flow or
        /// reducing the burned of cancellation safety or fuse semantics.
        ///
        /// ## Merging Streams
        ///
        /// For cases where `loop { select! { ... } }` is used to poll multiple tasks,
        /// stream merging offers a concise alternative, inherently handle cancellation-safe
        /// processing, removing the risk of data loss. Libraries like
        /// [`tokio-stream`](https://docs.rs/tokio-stream/latest/tokio_stream/) and
        /// [`futures-concurrency`](https://docs.rs/futures-concurrency/latest/futures_concurrency/)
        /// provide tools for merging streams and handling their outputs sequentially.
        ///
        /// ### Example with `select!`
        ///
        /// ```ignore
        /// use std::pin::pin;
        ///
        /// struct File;
        /// struct Channel;
        /// struct Socket;
        ///
        /// impl Socket {
        ///     async fn read_packet(&mut self) -> Vec<u8> {
        ///         todo!()
        ///     }
        /// }
        ///

Review comment (bug):
This doesn't really explain why you would pick an alternative. As I see it, the primary reason to prefer alternatives is that `select!` can easily lead to bugs related to cancellation safety. I would focus the motivation in this section much more heavily on that.

Code after:
        ///
        /// To determine whether your own methods are cancellation safe, look for the
        /// location of uses of `.await`. This is because when an asynchronous method is
        /// cancelled, that always happens at an `.await`. If your function behaves
        /// correctly even if it is restarted while waiting at an `.await`, then it is
        /// cancellation safe.
        ///
        /// Cancellation safety can be defined in the following way: If you have a
        /// future that has not yet completed, then it must be a no-op to drop that
        /// future and recreate it. This definition is motivated by the situation where
        /// a `select!` is used in a loop. Without this guarantee, you would lose your
        /// progress when another branch completes and you restart the `select!` by
        /// going around the loop.
        ///
        /// Be aware that cancelling something that is not cancellation safe is not
        /// necessarily wrong. For example, if you are cancelling a task because the
        /// application is shutting down, then you probably don't care that partially
        /// read data is lost.
        ///
        /// # Examples
        ///
        /// Basic select with two branches.
        ///
        /// ```
        /// async fn do_stuff_async() {
        ///     // async work
        /// }
        ///
        /// async fn more_async_work() {
        ///     // more here
        /// }
        ///
        /// #[tokio::main]
        /// async fn main() {
        ///     tokio::select! {
        ///         _ = do_stuff_async() => {
        ///             println!("do_stuff_async() completed first")
        ///         }
        ///         _ = more_async_work() => {
        ///             println!("more_async_work() completed first")
        ///         }
        ///     };
        /// }
        /// ```
        ///
        /// Basic stream selecting.
        ///
        /// ```
        /// use tokio_stream::{self as stream, StreamExt};
        ///
        /// #[tokio::main]