From a91d3c443b02e8d748db5eb926c37281067207bd Mon Sep 17 00:00:00 2001 From: XperiAndri Date: Mon, 5 Oct 2026 02:12:58 +0200 Subject: [PATCH] fix(task)!: default `ofTask` `configureAwait` to `true` Both `ofTask` overloads declared `[] configureAwait` without a default value, so an omitted argument passed `false`, while R3's `FromAsync`, `ofAsync`, `ProcessingOptions.Default` and `ChunkConfiguration.AsyncWindow` all default to `true`. A UI handler subscribed through `ofTask` therefore ran off its synchronization context. The parameter now defaults to `true`, and both overloads are documented. BREAKING CHANGE: callers that omit `configureAwait` now resume on the captured synchronization context; pass `false` to keep the old behaviour. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 1 + src/FSharp.Control.R3/TaskObservable.fs | 22 ++++++++++++++++++---- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a8b750c..b73f924 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -19,6 +19,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - **Breaking:** `AwaitOperationConfiguration` cases are prefixed with `Await` (`AwaitSequential`, `AwaitParallel 4`, ...) so they no longer collide with `System.Threading.Tasks.Parallel` - **Breaking:** the `Async` functions raise the original exception instead of an `AggregateException`, and a cancelled operation cancels the computation instead of failing it - **Breaking:** the `Async` `toLookup` overloads no longer take a `cancellationToken`; they observe the token of the computation +- **Breaking:** `ofTask` defaults `configureAwait` to `true`, like R3 and `ofAsync` - **Breaking:** the `OptionExtensions`/`ValueOptionExtensions` types are replaced by `Observable.choose`, which takes a `voption` chooser, and `ObservableOption.choose` for `option`; the `Observable.Extensions` type is replaced by `Observable.ofSeq` - **Breaking:** after `open FSharp.Control.R3`, `Observable.choose` is the R3 function, like `Observable.map` and `Observable.filter` already were; use `Microsoft.FSharp.Control.Observable.choose` for `IObservable` and F# events - **Breaking:** after `open FSharp.Control.R3`, the bare type name `Observable` refers to `FSharp.Control.R3.ObservableFactories.Observable`; write `open type R3.Observable` and extend `R3.Observable` by its full name diff --git a/src/FSharp.Control.R3/TaskObservable.fs b/src/FSharp.Control.R3/TaskObservable.fs index 122d55f..ca77f4f 100644 --- a/src/FSharp.Control.R3/TaskObservable.fs +++ b/src/FSharp.Control.R3/TaskObservable.fs @@ -114,15 +114,29 @@ module Extensions = type Observable private () = /// - /// Creates observable sequence from a single element returned by cancellable + /// Creates an observable sequence that invokes the factory on every subscription, emits + /// when its completes, and then completes. + /// + /// Disposing the subscription cancels the token passed to the factory. A failure of the task completes the sequence + /// with that failure. (true by default) defines whether the continuation + /// resumes on the captured synchronization context. + /// /// - static member inline ofTask (asyncFactory : CancellationToken -> ValueTask, [] configureAwait) = + static member inline ofTask (asyncFactory : CancellationToken -> ValueTask, [] configureAwait : bool) = Observable.FromAsync (asyncFactory, configureAwait) /// - /// Creates observable sequence from a single element returned by cancellable + /// Creates an observable sequence that invokes the factory on every subscription, emits the result of its + /// , and then completes. + /// + /// Disposing the subscription cancels the token passed to the factory. A failure of the task completes the sequence + /// with that failure. (true by default) defines whether the continuation + /// resumes on the captured synchronization context. + /// /// - static member inline ofTask (asyncFactory : CancellationToken -> ValueTask<'T>, [] configureAwait) = + static member inline ofTask + (asyncFactory : CancellationToken -> ValueTask<'T>, [] configureAwait : bool) + = Observable.FromAsync (asyncFactory, configureAwait) static member inline toArray (source, [] cancellationToken) = ObservableExtensions.ToArrayAsync (source, cancellationToken)