Skip to content

Commit

Permalink
Align IntroToRx Start description with reality (#2163)
Browse files Browse the repository at this point in the history
  • Loading branch information
idg10 authored Aug 28, 2024
1 parent 5f831de commit 840fa39
Showing 1 changed file with 3 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -811,7 +811,7 @@ Although we've now seen two very general ways to produce arbitrary sequences—`

### From delegates

The `Observable.Start` method allows you to turn a long running `Func<T>` or `Action` into a single value observable sequence. By default, the processing will be done asynchronously on a ThreadPool thread. If the overload you use is a `Func<T>` then the return type will be `IObservable<T>`. When the function returns its value, that value will be published and then the sequence completed. If you use the overload that takes an `Action`, then the returned sequence will be of type `IObservable<Unit>`. The `Unit` type represents the absence of information, so it's somewhat analogous to `void`, except you can have an instance of the `Unit` type. It's particularly useful in Rx because we often care only about when something has happened, and there might not be any information besides timing. In these cases, we often use an `IObservable<Unit>` so that it's possible to produce definite events even though there's no meaningful data in them. (The name comes from the world of functional programming, where this kind of construct is used a lot.) In this case, `Unit` is used to publish an acknowledgement that the `Action` is complete, because an `Action` does not return any information. The `Unit` type itself has no value; it just serves as an empty payload for the `OnNext` notification. Below is an example of using both overloads.
The `Observable.Start` method allows you to turn a long running `Func<T>` or `Action` into a single value observable sequence. The action is invoked through a [scheduler](11_SchedulingAndThreading.md#schedulers). If you don't pass a scheduler explicitly, this will use the [`DefaultScheduler`](11_SchedulingAndThreading.md#defaultscheduler), which invokes the callback via the thread pool. If the overload you use is a `Func<T>` then the return type will be `IObservable<T>`. When the function returns its value, the `IObservable<T>`, will supply that value to subscribers and then complete immediately after supplying the value. (The `IObservable<T>` that `Start` returns is based on [`AsyncSubject`](#asyncsubjectt), so if you subscribe to it after the callback has completed, it will immediately supply the value and then complete.) If you use the overload that takes an `Action`, then the returned sequence will be of type `IObservable<Unit>`. The `Unit` type represents the absence of information, so it's somewhat analogous to `void`, except you can have an instance of the `Unit` type. It's particularly useful in Rx because we often care only about when something has happened, and there might not be any information besides timing. In these cases, we often use an `IObservable<Unit>` so that it's possible to produce definite events even though there's no meaningful data in them. (The name comes from the world of functional programming, where this kind of construct is used a lot.) In this case, `Unit` is used to publish an acknowledgement that the `Action` is complete, because an `Action` does not return any information. The `Unit` type itself has no value; it just serves as an empty payload for the `OnNext` notification. Below is an example of using both overloads.

```csharp
static void StartAction()
Expand Down Expand Up @@ -850,9 +850,9 @@ static void StartFunc()
}
```

Note the difference between `Observable.Start` and `Observable.Return`. The `Start` method invokes our callback only upon subscription, so it is an example of a 'lazy' operation. Conversely, `Return` requires us to supply the value up front.
Note the difference between `Observable.Start` and `Observable.Return`. `Return` requires us to supply the value up front, whereas `Start` returns an observable sequence immediately, without needing the value to be available. (Although `Start` doesn't wait for the callback to complete, it does invoke it immediately. So this is not lazy evaluation—if you want to supply a callback that will be invoked only when someone subscribes to the source, use [`Defer`](#observabledefer).)

The observable returned by `Start` may seem to have a superficial resemblance to `Task` or `Task<T>` (depending on whether you use the `Action` or `Func<T>` overload). Each represents work that may take some time before eventually completing, perhaps producing a result. However, there's a significant difference: `Start` doesn't begin the work until you subscribe to it. Moreover, it will re-execute the callback every time you subscribe to it. So it is more like a factory for a task-like entity.
The observable returned by `Start` can be thought of as representing the same basic idea as `Task` or `Task<T>` (depending on whether you use the `Action` or `Func<T>` overload). Each represents work that may take some time before eventually completing, perhaps producing a result. So `Start` is useful if you want that basic idea, but for it to be represented as an `IObservable<T>` instead of a `Task` or `Task<T>`.

### From events

Expand Down

0 comments on commit 840fa39

Please sign in to comment.