Repository navigation
docs: add ADR 0002 for EquatableArray - #24
Open
xperiandri wants to merge 5 commits into
Open
xperiandri wants to merge 5 commits into
xperiandri wants to merge 5 commits into
Conversation
There was a problem hiding this comment.
🟡 Changes recommended
The differing key equivalence under equality and ordering needs an explicit design decision and test coverage plan.
1 open issue
What changed in this PR
Adds a proposed ADR for EquatableArray<'T>, a value-semantic wrapper alongside FlatList. No library code changes.
Changes:
- Defines equality, ordering, default-value behavior and interop.
- Plans module integration, tests and staged delivery alongside ADR 0001.
- Records seven questions for maintainers.
| File | Description |
|---|---|
| docsSrc/Explanations/ADR_0002_EquatableArray.md | Documents the proposed type, contracts and delivery plan. |
Review effort: Balanced
4 of 6 tasks
Proposes `EquatableArray<'T>`, a struct over one `ImmutableArray<'T>`
with value semantics:
- the default value is the empty array;
- equality and hashing cover all elements with
`EqualityComparer<'T>.Default`, also through C# `==` and `!=`;
- comparison is by length first, then in the order of F# generic
comparison;
- O(1) conversion to and from `ImmutableArray<'T>`, C# collection
expressions, C# ranges through `Slice`, and System.Text.Json without
registration;
- a module that mirrors `FlatList`, struct active patterns and the
`equatableArray { }` computation expression, delivered in two steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
`EqualityComparer<'T>.Default` compares F# arrays, `FlatList`s and tuples that hold them by reference, while F# comparison compares their contents. Two `EquatableArray<int[]>` values with equal but separately allocated inner arrays are therefore not equal under `Equals` but compare as 0, so a default `HashSet` keeps two values where a `Set` keeps one. - Decision 5 accepts this explicitly; the later decisions move down. - §2 (Keys) lists the element types that agree and the measured result of each caller for those that do not, including `CompareTo` throwing on `FlatList` elements of different lengths. - §3 points from the choice of element comparers to §2. - §7 adds the regression tests. - Question 8 offers the alternative, comparing such elements by contents, with its measured cost. - §2 and §10: array elements compare by reference also inside struct tuples, and by contents in `CompareTo`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The maintainers accepted every recommendation of section 11 on 2026-10-18, and pull request #28 implements step 1. - Status Accepted; section 11 records the decisions. - Section 1: the library compiles against the signature, `Slice` included. - Sections 5 and 6: step 1 also has `unsafeOfArray`, which throws for `null` like `ofArray`. - Section 7: the categories as implemented, the exact allocation counts, and the C# test project that the maintainers chose. - Section 9: the four differences the first consumer notices when it moves to the library type. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
force-pushed
the
docs/equatable-array-design
branch
from
October 18, 2026 13:03
c90668b to
8406ec3
Compare
Section 7 put an operation category on the tests of module functions through `TestCategory (nameof ...)`. The test category rules now put the `TestCategories.fs` attributes on the test classes only, as ADR 0001 D8 does, so test methods carry none and the module tests get `ModuleFunctionsTestCategory`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Section 2 states the depth guard of the display text: each nested display starts a new %A formatter, so a guard shared by them shows "..." at a nesting of 100 (the Copilot review of pull request #28). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
xperiandri
force-pushed
the
main
branch
2 times, most recently
from
October 20, 2026 16:16
5d56ba0 to
9d7316e
Compare
This branch has not been deployed
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.

Proposed Changes
Adds
docsSrc/Explanations/ADR_0002_EquatableArray.md, an architecture decision record forEquatableArray<'T>: a struct over oneImmutableArray<'T>with value semantics, for fields of records and unions, dictionary and set keys and persisted documents. It decides that the default value is the empty array, that equality and hashing cover all elements withEqualityComparer<'T>.Default(also for C#==and!=), and that comparison is by length first, in the order of F# generic comparison. For elements that are F# arrays,FlatLists or tuples that hold them, equality and comparison disagree on keys; the ADR accepts this explicitly and pins it with regression tests. It also covers O(1) conversion to and fromImmutableArray<'T>, C# collection expressions and ranges throughSlice, a System.Text.Json converter, struct active patterns, a module that mirrorsFlatList, and delivery in two steps.Status: Accepted. The maintainers accepted every recommendation of §11 on 2026-10-18, and §11 now records the decisions. Step 1 of §6 is implemented in #28; the ADR now matches what it ships (
unsafeOfArrayin step 1, the test categories, a C# test project in CI, and the four differences the first consumer notices).Types of changes
What types of changes does your code introduce to FSharp.Collections.Immutable?
Put an
xin the boxes that applyDocumentation only: the ADR describes a new type, which #28 adds; this pull request changes no code.
Checklist
Put an
xin the boxes that apply. You can also fill these out after creating the PR. If you're unsure about any of them, don't hesitate to ask. We're here to help! This is simply a reminder of what we are going to look for before merging your code.Further comments
ADR 0002 meets ADR 0001 (#23) in §5 to §7, and the two documents are aligned: the module mirrors the
FlatListmodule of ADR 0001 with itsOptionandTupleoverride modules, the patterns are struct partial patterns in both, element comparison avoids culture-sensitive comparers in both, and the mirror is one link of the ADR 0001 pull request chain.Facts marked (verified) were checked in
dotnet fsiand on a prototype outside the repository. The C# range syntax throughSlicewas checked with a C# program against an F# struct. The tests of #28 now pin these facts in F# and C#.🤖 Generated with Claude Code