-
Notifications
You must be signed in to change notification settings - Fork 1
Comparing changes
Open a pull request
base repository: fsprojects/FSharp.Control.R3
base: main
head repository: fsprojects/FSharp.Control.R3
compare: feat/task-to-array-to-list
- 18 commits
- 10 files changed
- 2 contributors
Commits on Oct 4, 2026
-
refactor!: prefix
AwaitOperationConfigurationcases withAwaitUnqualified cases such as `Parallel 4` collided with `System.Threading.Tasks.Parallel` (FS1133) whenever that namespace was opened after `FSharp.Control.R3`. The `Await` prefix mirrors the `Chunk` prefix of `ChunkConfiguration` and removes the collision. BREAKING CHANGE: `Sequential`, `Drop`, `Switch`, `Parallel`, `SequentialParallel` and `ThrottleFirstLast` become `AwaitSequential`, `AwaitDrop`, `AwaitSwitch`, `AwaitParallel`, `AwaitSequentialParallel` and `AwaitThrottleFirstLast`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for cfc4d47 - Browse repository at this point
Copy the full SHA cfc4d47View commit details
Commits on Oct 5, 2026
-
fix: validate the concurrency limit of
mapAsyncoptions eagerlyR3 rejects a `MaxConcurrent` of 0 or below -1 only when the mapped sequence is subscribed, typically far away from the code that built the options. Both flavours of `mapAsync` (and hence `iterAsync`) now throw `ArgumentOutOfRangeException` when they are called, through an internal `ProcessingOptions.Validate`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 7110fb7 - Browse repository at this point
Copy the full SHA 7110fb7View commit details -
fix(rxquery): emit
yield/zerosynchronously to keep element order`Yield` and `Zero` used `Observable.Return/Empty (TimeProvider.System)`, which R3 schedules on the thread pool. Every element of a query therefore hopped to another thread, `SelectMany` merged them in arbitrary order and the results arrived after the source had moved on, so `take`, `head`, `last`, `zip` and friends were nondeterministic. Both now emit synchronously on subscription. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 6dc3875 - Browse repository at this point
Copy the full SHA 6dc3875View commit details -
fix(rxquery)!: stop seeding
sumBywithUnchecked.defaultofThe fold started from `Unchecked.defaultof`, so a reference type that defines `(+)` received `null` as the first operand and faulted. The first element now seeds the sum; an empty source still yields the default value, so numeric and `TimeSpan` sums keep returning zero. BREAKING CHANGE: `sumBy` adds values of the projected type, so it requires `(+) : 'Value * 'Value -> 'Value`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for d657825 - Browse repository at this point
Copy the full SHA d657825View commit details -
feat(rxquery): add
rxqueryWithto cancel the terminal query operatorsThe query operators that return a task (`count`, `head`, `iter`, ...) called the R3 operators without a token, so a query over a hot source could not be cancelled and kept its subscription alive. `RxQueryBuilder` now carries a `CancellationToken` that every such operator observes; `rxquery` keeps using `CancellationToken.None` and `(rxqueryWith ct) { ... }` passes a token. The `Builders` module opens `System.Threading` for the token instead of repeating the file-level `open System`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for 1f025e7 - Browse repository at this point
Copy the full SHA 1f025e7View commit details -
docs(rxquery): document the query builder and every query operator
Every member of `RxQueryBuilder` now has XML documentation that states what the query operator does and, for the operators that return a task, when it completes or fails; the `Builders` module is documented too. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 4b9f059 - Browse repository at this point
Copy the full SHA 4b9f059View commit details -
feat(observable)!: make
ofSeqreachable asObservable.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 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for a3a2594 - Browse repository at this point
Copy the full SHA a3a2594View commit details -
feat(observable)!: make
Observable.choosetake avoptionchooser,…… add `ObservableOption` `Observable.choose` always resolved to FSharp.Core's `IObservable` version (FS0001) after `open FSharp.Control.R3`, because the R3 variants were static members of types in AutoOpen modules nested inside the non-AutoOpen `Observable` module. Their `[<Extension>]` members also added `.choose` to every F# function value. `choose` is now a function of the `Observable` module, which shadows FSharp.Core's `Observable.choose`. Like every function of the library that works with optional values it takes a `voption` chooser, which does not allocate. The `option` variant lives in the new `ObservableOption` module, which requires qualified access: `ObservableOption.choose`. BREAKING CHANGE: the `OptionExtensions` and `ValueOptionExtensions` types are removed; `Observable.choose` takes `'T -> 'R voption`, use `ObservableOption.choose` for `'T -> 'R option`. After `open FSharp.Control.R3`, `Observable.choose` is the R3 function; use `Microsoft.FSharp.Control.Observable.choose` for `IObservable` and F# events. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for cdb1a60 - Browse repository at this point
Copy the full SHA cdb1a60View commit details -
feat(observable): add
chunkByBoundariesfor boundaries of any eleme……nt type `ChunkWindowBoundaries` reuses the element type of the source for the boundary sequence, although R3 ignores the boundary values, so chunking by `Observable<Unit>` ticks or a trigger subject required a dummy `map`. `chunkByBoundaries` passes boundaries of any element type to R3. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 6de0d51 - Browse repository at this point
Copy the full SHA 6de0d51View commit details -
fix(observable): validate every chunk length eagerly
R3 validates the window length of `Chunk(count)` when it is called, but not of the time-and-count overloads: a length of 0 made every element fail with `IndexOutOfRangeException` through `OnErrorResume`, and a negative one failed only at subscription with `OverflowException`. Where R3 does validate, it reports its message as the parameter name and leaves out the rejected value. `chunkBySize` and `chunkBy` now reject a non-positive length of `ChunkCount`, `ChunkTimeSpanCount` and `ChunkMillisecondsCount` when they are called, with an `ArgumentOutOfRangeException` that names the parameter and carries the rejected length. Both functions are no longer inline, because the shared check is private. Their XML docs are rewritten along with them: they document the `ArgumentOutOfRangeException` and the last chunk emitted on completion, and drop the `ArgumentNullException` tag. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 926f7ad - Browse repository at this point
Copy the full SHA 926f7adView commit details -
docs: document the processing and chunk configuration types
- `AwaitParallel` and `AwaitSequentialParallel` send up to `MaxConcurrent` values to the selector at once and queue the others, instead of sending all values at once. - `ProcessingOptions`: document every field, `Default`, `Parallel`, `MaxConcurrent` and `AwaitOperation`. `ConfigureAwait` configures only R3's await of the selector result, not the awaits inside the selector, and `CancelOnCompleted` also discards the queued elements. - `ChunkConfiguration`: document every case and case field, and point from `ChunkWindowBoundaries` to `chunkByBoundaries`; the helpers read the default time provider when they are called. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for cb9fb30 - Browse repository at this point
Copy the full SHA cb9fb30View commit details -
docs(observable): correct misleading XML docs and document every func…
…tion - `catch`: the remark "Exception does not stop further processing" was wrong; the handler only sees terminal failures of its exception type, the failed source is not resumed and `OnErrorResume` passes through. - `concat`: state that `a |> concat b` emits `b` first. - `bind`: an inner failure fails the result only while the source runs. - `cast`: an invalid cast is reported through `OnErrorResume`, and a null element cast to a value type as a `NullReferenceException`. - `skip`/`take`: a negative count throws when called; `take 0` completes at once without subscribing. - Document the module, `ofType` and the error behaviour of `map`, `filter` and `where`, and fix the copied typos ("identy", "upn", the question mark in `take`). - Name the `mapi` lambda parameters after the element and the index that R3 passes; the behaviour is unchanged. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>Configuration menu - View commit details
-
Copy full SHA for b54156b - Browse repository at this point
Copy the full SHA b54156bView commit details -
fix(async)!: remove the ignored
cancellationTokenfromtoLookupThe four `Async` `toLookup` overloads declared an untyped `[<Optional>] cancellationToken` that they never used. Being generic, it also swallowed a positional third or fourth argument, so `Observable.toLookup (source, keySelector, comparer)` silently ignored the comparer and a positional `elementSelector` was dropped. The parameter is removed: like every other `Async` function the overloads observe the token of the computation, and positional arguments now resolve like in the `Task` flavour. The type also drops its unused `[<Extension>]` attribute, since none of its members is an extension member. BREAKING CHANGE: callers passing `cancellationToken =` by name must start the computation with that token instead. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 6731321 - Browse repository at this point
Copy the full SHA 6731321View commit details -
fix(async)!: surface the original exception and cancellation from Asy…
…nc wrappers Every `Async` terminal function ended with `Async.AwaitTask`, which raises the `AggregateException` of a faulted task and turns a cancelled task into a failure. `try ... with :? InvalidOperationException` inside `async` therefore never matched, while the `Task` flavour surfaced the R3 exception directly. An internal helper keeps `Async.AwaitTask`, which resumes on the synchronization context that was current when the computation started to wait, and only translates its outcome: the single inner exception of an `AggregateException` is raised through the continuations, which keeps its stack trace, and a cancelled task cancels the computation. Both flavours now have the same error surface. `toArray` is no longer inline, because the helper is internal. BREAKING CHANGE: code that caught `AggregateException` from the `Async` functions now receives the inner exception, and a cancelled operation cancels the computation instead of failing it. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for b841076 - Browse repository at this point
Copy the full SHA b841076View commit details -
fix: wait for
iterAsyncthroughForEachAsyncinstead ofCountAsyncBoth flavours of `iterAsync` waited for completion by counting the mapped elements, and R3 counts with a `checked` add, so a long-lived source with more than `Int32.MaxValue` elements faulted with `OverflowException` although nothing asked for a count. They now wait through `iter`, which ignores the elements. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for e02cc31 - Browse repository at this point
Copy the full SHA e02cc31View commit details -
fix: stop
iterAsyncreliably and never lose a failure of its actionComposing R3's `SelectAwait` with `ForEachAsync` left four gaps in both flavours of `iterAsync`: - Over a synchronous source, R3 attaches the terminal to the mapped stage only after `Subscribe` returns, so the action kept running for every element after it had thrown. - With an already cancelled token the action still ran for every element of a synchronous source, although the iteration was cancelled. - R3 drops a failure of the action that happens after the source completed, so the iteration completed successfully. - `SelectAwait` swallows an `OperationCanceledException`: a timeout such as HttpClient's `TaskCanceledException` stopped the sequential worker for good and `iterAsync` never completed. The action's exceptions no longer travel through R3 at all. An internal `IterationGuard` records the first one, skips the remaining actions and cancels an internal token that completes the iteration through `TakeUntil`, which also unsubscribes from the source at once; the iteration then fails with the recorded exception. A cancellation that R3 itself caused for an invocation (`AwaitSwitch`, `CancelOnCompleted`, disposal) is not a failure, and a cancelled token cancels the iteration without subscribing. The `iterAsync` docs now describe which elements reach the action, when the iteration completes, also with `CancelOnCompleted`, and how it fails. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 5ce361d - Browse repository at this point
Copy the full SHA 5ce361dView commit details -
fix(task)!: default
ofTaskconfigureAwaittotrueBoth `ofTask` overloads declared `[<Optional>] 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 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 8245ea4 - Browse repository at this point
Copy the full SHA 8245ea4View commit details -
feat(task)!: move
toArrayandtoListinto theTask.Observablem……odule As static members of the extension type, `Observable.toArray` and `Observable.toList` always bound to the `Async` module functions when both flavours were opened (module lookup wins over type lookup), and `Task.Observable.toArray` did not exist. They are now curried functions of the `Task.Observable` module that take the token first, like `length`, `iter` and the other `Task` functions. The `Extensions` type also drops its unused `[<Extension>]` attribute and annotates the `toLookup` parameters like the Async type does; the compiled signatures of `toLookup` do not change. BREAKING CHANGE: `Observable.toArray (source, ct)` becomes `Observable.toArray ct source`, likewise for `toList`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Configuration menu - View commit details
-
Copy full SHA for 9ce0c5c - Browse repository at this point
Copy the full SHA 9ce0c5cView commit details
This comparison is taking too long to generate.
Unfortunately it looks like we can’t render this comparison for you right now. It might be too big, or there might be something weird with your repository.
You can try running this command locally to see the comparison on your machine:
git diff main...feat/task-to-array-to-list