feat(dummies): add top-level OneOf/ElementOf choice combinator#282
Merged
Conversation
Picking an arbitrary element from a caller-held set was the one common dummy need with no seed-aware answer: users hand-rolled pool[new Random().Next(...)], which ignores the ambient source and silently breaks Reproducibly for that draw. The typed builders' OneOf only narrows within a scalar's own domain; there was no way to draw from a pool of arbitrary domain objects. Add AnyOneOf<T>, a terminal generator drawing one value uniformly from an explicit pool, and the top-level factories Any.OneOf<T>(params T[]), Any.ElementOf<T>(IReadOnlyList<T>) and Any.ElementOf<T>(IEnumerable<T>) (the sequence overload materializes once), mirrored on AnyContext so the seeded surface carries them too. Two names avoid the params-generic inference footgun: OneOf for inline literals, ElementOf for a held collection. The pool is deduplicated, sized and membership-tested under EqualityComparer<T>.Default - the type-agnostic analogue of the string generator's ordinal dedup, and a sound upper bound for the distinct- collection cardinality gate (ADR-0013). An empty pool throws eagerly; a null element is rejected and the message points at OrNull(), keeping nullability orthogonal and symmetric with Any.String().OneOf (ADR-0030). The Any<->AnyContext mirror is enforced by SurfaceParityTests; the generic, parameterized factories are excluded from the CLR-naming and cross-engine guards by construction. Covered by AnyOneOfTests. Record the decision as ADR-0032 (Proposed): draw arbitrary values from an explicit, top-level choice pool. Refs: #223 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQ15y5om7Gagin9ZpYXDWf
Document the top-level choice combinator in the Dummies package README: Any.OneOf(...) and Any.ElementOf(...) as the seed-aware answer to "any of these", mirroring where the string value-set generator is documented. Record the maintainer's acceptance of ADR-0032 (draw arbitrary values from an explicit, top-level choice pool): flip its status from Proposed to Accepted in the English and French records and in the ADR index. The Dummies CHANGELOG [Unreleased] section is drafted automatically from merged pull requests (changelog.yml), so it is left untouched here. Refs: #223 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQ15y5om7Gagin9ZpYXDWf
Merging main brought in the per-target-framework public API baselines (#221): PublicApiAnalyzers now raises RS0016 for any public symbol absent from PublicAPI.Unshipped.txt, a warning locally and an error in CI. The new top-level choice combinator was therefore undeclared and reddened the build, pack and packaged-asset jobs. Declare the eight new public symbols - AnyOneOf<T>, its Generate(), and the OneOf/ElementOf factories on Any and AnyContext - in both the net8.0 and netstandard2.0 baselines. The entries are identical across the two assets because the combinator is not gated by #if NET8_0_OR_GREATER. Verified locally: dotnet pack -c Release is clean (no RS0016, package validation passes) and the full solution builds warning-free. Refs: #223 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LQ15y5om7Gagin9ZpYXDWf
Reefact
enabled auto-merge
July 21, 2026 22:04
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Add a top-level, seed-aware choice combinator to
Dummies:Any.OneOf<T>(params T[])andAny.ElementOf<T>(...)draw one value uniformly from a caller-supplied pool, so picking "any of these" no longer needs a hand-rolledpool[new Random().Next(...)]that ignores the ambient seed and silently breaksReproducibly. This is the audit's highest-leverage Must-Have (§10).Type of change
Changes
AnyOneOf<T>— a terminal generator drawing uniformly from an explicit pool (IAny<T>,IHasRandomSource,ICardinalityHint<T>); the pool is deduplicated, sized and membership-tested underEqualityComparer<T>.Default.Any.OneOf<T>(params T[]),Any.ElementOf<T>(IReadOnlyList<T>)andAny.ElementOf<T>(IEnumerable<T>)(the sequence overload materializes once), mirrored onAnyContextfor the seeded surface.params-generic inference footgun:OneOffor inline literals,ElementOffor a held collection.nullelement is refused with a message pointing atOrNull(), keeping nullability orthogonal and symmetric withAny.String().OneOf(ADR-0030).Dummies.UnitTests/AnyOneOfTests.cs; theAny↔AnyContextmirror is enforced by the existingSurfaceParityTests.Testing
dotnet build FirstClassErrors.slndotnet test FirstClassErrors.slnFirstClassErrors.Analyzers.UnitTests)Ran
dotnet test Dummies.UnitTests→ 440/440 passed (the new tests plus the parity / naming / cross-engine / architecture guards). BuiltDummieson both target frameworks (netstandard2.0+net8.0) clean, 0 warnings. Did not run the full-solution test suite or the analyzer tests — no analyzer change in this PR.Documentation
doc/updateddoc/handwritten/for-users/README.fr.md) updated if user-facing behavior changedXML docs on the new factories and
AnyOneOf<T>; the Dummies package README (README.nuget.md) gains a bullet with an example. ADR-0032 ships bilingual (EN + FR).README.fr.mdneeds no change — the root README does not reference the Dummies package.Architecture decisions
Proposed: ADR-0032ADR-0032 was drafted as
Proposedand accepted by the maintainer (@Reefact) during this session — recorded asAccepted. It complements ADR-0030 (the string sibling) and relies on ADR-0013 (theICardinalityHintcardinality gate); no accepted ADR is contradicted.Related issues
Closes #223
Generated by Claude Code