Skip to content

docs: add ADR 0002 for EquatableArray - #24

Open
xperiandri wants to merge 5 commits into
mainfrom
docs/equatable-array-design
Open

xperiandri wants to merge 5 commits into
mainfrom
docs/equatable-array-design

Conversation

@xperiandri

@xperiandri xperiandri commented Oct 17, 2026 •

Copy link
Copy Markdown
Collaborator

Proposed Changes

Adds docsSrc/Explanations/ADR_0002_EquatableArray.md, an architecture decision record for EquatableArray<'T>: a struct over one ImmutableArray<'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 with EqualityComparer<'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 from ImmutableArray<'T>, C# collection expressions and ranges through Slice, a System.Text.Json converter, struct active patterns, a module that mirrors FlatList, 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 (unsafeOfArray in 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 x in the boxes that apply

  • Bugfix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)

Documentation only: the ADR describes a new type, which #28 adds; this pull request changes no code.

Checklist

Put an x in 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.

  • Build and tests pass locally (not run for this pull request – it changes one Markdown file; CI builds it)
  • I have added tests that prove my fix is effective or that my feature works (not applicable – documentation only)
  • I have added necessary documentation (if appropriate)

Further comments

ADR 0002 meets ADR 0001 (#23) in §5 to §7, and the two documents are aligned: the module mirrors the FlatList module of ADR 0001 with its Option and Tuple override 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 fsi and on a prototype outside the repository. The C# range syntax through Slice was 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

Copilot AI balanced review requested due to automatic review settings October 17, 2026 22:59

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Comment thread docsSrc/Explanations/ADR_0002_EquatableArray.md Outdated
xperiandri and others added 3 commits October 18, 2026 14:51
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
xperiandri force-pushed the docs/equatable-array-design branch from c90668b to 8406ec3 Compare October 18, 2026 13:03
xperiandri and others added 2 commits October 18, 2026 15:09
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
xperiandri force-pushed the main branch 2 times, most recently from 5d56ba0 to 9d7316e Compare October 20, 2026 16:16

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants