From 71f3f94660650fd663bb8cafa9c612c7d6ca546a Mon Sep 17 00:00:00 2001 From: XperiAndri Date: Mon, 5 Oct 2026 02:12:29 +0200 Subject: [PATCH] feat(observable)!: make `ofSeq` reachable as `Observable.ofSeq` `Observable.ofSeq` was undefined (FS0039) after `open FSharp.Control.R3`, because the member lived on a type in an AutoOpen module nested inside the non-AutoOpen `Observable` module. `ofSeq` moves to the new AutoOpen `ObservableFactories` module that sits directly in the namespace, with an overload taking a `CancellationToken`. Name resolution of `Observable.ofSeq` finds no such function in the modules named `Observable` and falls through to the type, the same way `Observable.ofTask` resolves after opening `FSharp.Control.R3.Task`. BREAKING CHANGE: the `Observable.Extensions` type is removed. 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. Co-Authored-By: Claude Opus 5.5 --- .github/copilot-instructions.md | 1 + CHANGELOG.md | 3 ++ .../FSharp.Control.R3.fsproj | 1 + src/FSharp.Control.R3/Observable.fs | 9 ---- src/FSharp.Control.R3/ObservableFactories.fs | 46 +++++++++++++++++++ 5 files changed, 51 insertions(+), 9 deletions(-) create mode 100644 src/FSharp.Control.R3/ObservableFactories.fs diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index 6a69e81..c643711 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -16,6 +16,7 @@ │ ├── AssemblyInfo.fs – assembly metadata │ ├── ProcessingOptions.fs – processing configuration helpers │ ├── Observable.fs – observable wrappers/extensions +│ ├── ObservableFactories.fs – factories reachable as `Observable.xxx` (`ofSeq`) │ ├── AsyncObservable.fs – async observable helpers │ └── TaskObservable.fs – task-based observable helpers ├── tests/FSharp.Control.R3.Tests/ – MSTest test project diff --git a/CHANGELOG.md b/CHANGELOG.md index 63d3ec8..9d4f319 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,11 +9,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- `Observable.ofSeq (items)` and `Observable.ofSeq (items, cancellationToken)`, reachable after `open FSharp.Control.R3` - `rxqueryWith cancellationToken` and `RxQueryBuilder (cancellationToken)` to cancel the query operators that return a task ### Changed - **Breaking:** `AwaitOperationConfiguration` cases are prefixed with `Await` (`AwaitSequential`, `AwaitParallel 4`, ...) so they no longer collide with `System.Threading.Tasks.Parallel` +- **Breaking:** the `Observable.Extensions` type is replaced by `Observable.ofSeq` +- **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 - **Breaking:** `rxquery` `sumBy` adds values of the projected type: it requires `(+) : 'Value * 'Value -> 'Value` - `mapAsync` and `iterAsync` validate the concurrency limit of the options when they are called diff --git a/src/FSharp.Control.R3/FSharp.Control.R3.fsproj b/src/FSharp.Control.R3/FSharp.Control.R3.fsproj index c8c433d..cb270e1 100644 --- a/src/FSharp.Control.R3/FSharp.Control.R3.fsproj +++ b/src/FSharp.Control.R3/FSharp.Control.R3.fsproj @@ -19,6 +19,7 @@ + diff --git a/src/FSharp.Control.R3/Observable.fs b/src/FSharp.Control.R3/Observable.fs index 003921f..3078610 100644 --- a/src/FSharp.Control.R3/Observable.fs +++ b/src/FSharp.Control.R3/Observable.fs @@ -75,15 +75,6 @@ let inline take (count : int) (source) = ObservableExtensions.Take (source, coun let inline where ([] f : 'T -> bool) source = ObservableExtensions.Where (source, f) open System.Runtime.CompilerServices -open System.Runtime.InteropServices - -[] -module Extensions = - - [] - type Observable private () = - - static member ofSeq (items : _ seq, [] cancellationToken) = Observable.ToObservable (items, cancellationToken) [] module OptionExtensions = diff --git a/src/FSharp.Control.R3/ObservableFactories.fs b/src/FSharp.Control.R3/ObservableFactories.fs new file mode 100644 index 0000000..97c9108 --- /dev/null +++ b/src/FSharp.Control.R3/ObservableFactories.fs @@ -0,0 +1,46 @@ +namespace FSharp.Control.R3 + +open System.Threading +open R3 + +/// +/// Factories of observable sequences that are reachable through the type name Observable +/// as soon as is opened. +/// +/// This module sits directly in the namespace, so opening the namespace opens it too. +/// Name resolution of +/// finds no such function in the modules named Observable and falls through to the type +/// , the same way +/// +/// resolves after opening . R3's own factories, such as +/// , still resolve through the same name. +/// +/// +/// Where the bare type name matters, it now refers to this type: write open type R3.Observable rather than +/// open type Observable, and extend by its full name. +/// +/// +[] +module ObservableFactories = + + /// Factories of observable sequences. + [] + type Observable private () = + + /// + /// Creates an observable sequence that emits the elements of synchronously on every subscription + /// and then completes. + /// The sequence is enumerated to the end even when the subscriber unsubscribes earlier, so it must be finite. + /// + static member ofSeq (items : 'T seq) : Observable<'T> = R3.Observable.ToObservable items + + /// + /// Creates an observable sequence that emits the elements of synchronously on every subscription + /// and then completes. + /// + /// Once is cancelled, no further element is emitted and the sequence completes successfully. + /// The token is checked after the enumerator moved to the next element, so the side effects of producing that element still run. + /// + /// + static member ofSeq (items : 'T seq, cancellationToken : CancellationToken) : Observable<'T> = + R3.Observable.ToObservable (items, cancellationToken)