Skip to content

Commit 845174b

Browse files
xperiandriclaude
andcommitted
docs: align ADR 0001 with ADR 0002
- `IndexedList`, `Queue`, `Stack` and their interface modules get the struct partial patterns `Cons` and `Nil` instead of the multi-case `(|Cons|Nil|)`, which allocates a `Choice` per match (ADR 0002 §5). - Sorts avoid culture-sensitive comparers such as `Comparer<string>.Default`; `Comparer<'T>.Default` stays usable where it agrees with F# comparison, as ADR 0002 §3 uses it. - Operation test categories come from `nameof`, never from string literals; a contract base takes the name from any module. - `EquatableArray` is named in D1, in the computation expressions, in the pull request chain as `feat/equatable-array`, and in Appendix A; step 1 of ADR 0002 may ship from `main` before the chain. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 4cb6fde commit 845174b

1 file changed

Lines changed: 28 additions & 17 deletions

File tree

‎docsSrc/Explanations/ADR_0001_Collection_Modules.md‎

Lines changed: 28 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -50,13 +50,16 @@ New collections: `FrozenMap` (`FrozenDictionary<'Key, 'Value>`) and `FrozenSet`
5050
creation, lookup, iteration, folds, conversions **and** whole-collection transformations (`map`, `filter`, `choose`,
5151
`partition`, set algebra), each documented as an O(n) rebuild. They offer no incremental mutation (`add`, `remove`,
5252
`setItem`, `change`, `clear`, `addRange`, `removeRange`): a frozen collection is built once and read many times.
53+
ADR 0002 – EquatableArray (`ADR_0002_EquatableArray.md`) adds `EquatableArray<'T>`, an immutable array with value
54+
semantics, whose module mirrors `FlatList`.
5355

5456
Curated extras kept beyond FSharp.Core: `indexOf`/`indexOfWith`/`lastIndexOf`/`lastIndexOfWith`, `binarySearch`,
5557
`sortWithComparer`, `isDefault`/`isDefaultOrEmpty`, `asSpan`/`asMemory`/`ofSpan`/`ofReadOnlySpan`, the builder family
5658
(`builder`, `builderWith`, `ofBuilder`, `toBuilder`, `moveFromBuilder`, `build`, `update`), `blit`, `add`,
57-
`cons`/`uncons`/`tryUncons`/`(|Cons|Nil|)`, `tryTail`, `enqueue`/`enqueueMany`, `consMany`, `takeLast`/`skipLast`, `clear`
58-
on interface modules, `tryGetKey`/`tryGetValue`, `setItem`/`setItems`/`addRange`/`removeRange`, `containsValue`,
59-
`symmetricDifference`, `overlaps`/`setEquals`, comparer accessors and `with*Comparer` functions.
59+
`cons`/`uncons`/`tryUncons`, the struct partial patterns `(|Cons|_|)`/`(|Nil|_|)`, `tryTail`, `enqueue`/`enqueueMany`,
60+
`consMany`, `takeLast`/`skipLast`, `clear` on interface modules, `tryGetKey`/`tryGetValue`,
61+
`setItem`/`setItems`/`addRange`/`removeRange`, `containsValue`, `symmetricDifference`, `overlaps`/`setEquals`, comparer
62+
accessors and `with*Comparer` functions.
6063

6164
Removed from the started branch: `iter3`/`iteri3`/`exists3`/`forall3`/`mapi3`/`foldBack3`, `foldi`/`foldi2`/`foldBacki`/
6265
`foldBacki2`, `findDup`/`findDupBy`, `pickBack`/`tryPickBack`/`chooseBack`, the `From`/`Range` variants of `index*`/
@@ -76,7 +79,7 @@ Names: `IMap` module and `IMap<'Key, 'Value>` abbreviation for `IImmutableDictio
7679
Maps and sets measure their size with `count` (FSharp.Core `Map.count`/`Set.count`), sequences with `length`. `Queue` keeps
7780
`enqueue`/`head`/`tail`/`uncons` (compiled `Enqueue`/`Peek`/`Dequeue`/`PeekDequeue`), `Stack` keeps `cons`/`head`/`tail`/
7881
`uncons` (`Push`/`Peek`/`Pop`/`PeekPop`). Computation expression instances: `flatList`, `indexedList`, `queue`, `stack`,
79-
`hashMap`, `sortedMap`, `hashSet`, `sortedSet`, `frozenMap`, `frozenSet`.
82+
`hashMap`, `sortedMap`, `hashSet`, `sortedSet`, `frozenMap`, `frozenSet`, and `equatableArray` of ADR 0002.
8083

8184
### D3. Value-type defaults and the `Option`/`Tuple` override namespaces
8285

@@ -147,8 +150,9 @@ FSharp.Core module that a collection mirrors: `FlatList` and `FlatList.Parallel`
147150
`Array.Parallel.sort*` are documented ("This is not a stable sort"), through `ImmutableArray.Sort` or `Array.sort*` on the
148151
bridge; `IndexedList`, `Queue`, `Stack` and their interface modules sort stably, as `List.sort*` and `Seq.sort*` are
149152
documented, through LINQ `OrderBy`/`OrderByDescending` (documented stable), not through the unstable `ImmutableList.Sort`.
150-
Every sort compares with F# structural comparison (`LanguagePrimitives.FastGenericComparer<'T>`, the comparer behind
151-
`compare`), never with `Comparer<'T>.Default`, which compares strings culture-sensitively.
153+
Every sort compares in the order of F# generic comparison (`LanguagePrimitives.FastGenericComparer<'T>`, the comparer
154+
behind `compare`), never with a culture-sensitive comparer such as `Comparer<string>.Default`. ADR 0002 §3 shows the
155+
effect on strings and uses the same order for the elements of `EquatableArray`.
152156

153157
Consequences for the types: `FlatList` range operations (`take`, `skip`, `truncate`, `splitAt`, `takeLast`, `skipLast`,
154158
`chunkBySize`, `windowed`) copy the selected elements. An `ImmutableArray` is a single array reference without an offset or a
@@ -168,7 +172,7 @@ and the element comparer of a set are kept by `filter`, `partition` and set alge
168172
element type, so their result gets the default comparer of the new type. The interface modules cannot read the comparers
169173
of their input, so their type-changing transformations return concrete collections with default comparers. The defaults,
170174
which creation functions without a comparer argument also use, are `EqualityComparer<'T>.Default` for hash-based
171-
collections and the order of F# generic comparison
175+
collections, as ADR 0002 uses for equality, and the order of F# generic comparison
172176
(`LanguagePrimitives.FastGenericComparer<'T>`) for sorted collections. Thus `SortedSet<string>` is ordinal by default, as
173177
F# `Set<string>` is.
174178

@@ -223,18 +227,21 @@ observed enumeration order, so one test body serves FIFO, LIFO and indexed colle
223227
file. Expected exceptions come from the same oracle: the test calls the function of the mirrored FSharp.Core module (D6)
224228
on the same input and asserts the same type and message with `Assert.ThrowsExactly`; `ParamName` is checked against the
225229
ops record. Every assertion carries a message; categories come from `TestCategories.fs` attributes (collection level) and
226-
`TestCategory` strings or `nameof` (operation level). Dedicated files per collection prove that opening the
227-
`Option`/`Tuple` namespaces shadows the default functions and that the override functions are equivalent to the defaults
228-
after conversion.
230+
`TestCategory (nameof …)` (operation level), never from string literals. In a contract base, the function of any module
231+
gives the name, for example `nameof FlatList.map`. Dedicated files per collection prove that opening the `Option`/`Tuple`
232+
namespaces shadows the default functions and that the override functions are equivalent to the defaults after conversion.
229233

230234
### D9. Delivery: one pull request per collection, stacked
231235

232236
`chore/foundation` (helper module, order check script, test categories and contract bases, changelog and documentation
233237
skeleton, target frameworks), then `feat/flat-list`, `feat/flat-list-parallel` (the nested `Parallel` module of D11),
234-
`feat/indexed-list`, `feat/queue`, `feat/stack`, `feat/hash-map` (with `IMap`), `feat/sorted-map`, `feat/hash-set` (with
235-
`ISet`), `feat/sorted-set`, `feat/frozen-map`, `feat/frozen-set` (both with the alternate lookup of D11), and an optional
236-
`chore/benchmarks` (BenchmarkDotNet, excluded from the solution filter). Each pull request deletes the legacy file
237-
it replaces, keeps the build green and updates the changelog and the documentation table. No release is cut mid-chain.
238+
`feat/equatable-array` (step 2 of ADR 0002: the mirror of the `FlatList` module, its builder functions and
239+
`equatableArray { }`), `feat/indexed-list`, `feat/queue`, `feat/stack`, `feat/hash-map` (with `IMap`), `feat/sorted-map`,
240+
`feat/hash-set` (with `ISet`), `feat/sorted-set`, `feat/frozen-map`, `feat/frozen-set` (both with the alternate lookup of
241+
D11), and an optional `chore/benchmarks` (BenchmarkDotNet, excluded from the solution filter). Each pull request deletes
242+
the legacy file it replaces, keeps the build green and updates the changelog and the documentation table. No release is
243+
cut mid-chain.
244+
Step 1 of ADR 0002 (the `EquatableArray` type, its patterns and JSON converter) MAY ship from `main` before the chain.
238245

239246
### D10. Target frameworks
240247

@@ -351,7 +358,8 @@ their element-type-changing transformations return the concrete type.
351358
| `tryTail` | Ⓥ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | |
352359
| `tryUncons` | Ⓥ+Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | `struct ('T * X<'T>) voption` |
353360
| `uncons` | Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | compiled `PeekDequeue`/`PeekPop` |
354-
| `(\|Cons\|Nil\|)` | Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | |
361+
| `(\|Cons\|_\|)` | Ⓥ+Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | `[<return: Struct>]`, `struct ('T * X<'T>) voption`; a multi-case pattern allocates a `Choice` per match (ADR 0002 §5) |
362+
| `(\|Nil\|_\|)` | | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | returns `bool` |
355363
| **Search** | | | | | | | | | |
356364
| `binarySearch` | | ᵇ | ᵇ | – | – | – | – | – | BCL bitwise-complement contract |
357365
| `contains` | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
@@ -429,9 +437,12 @@ their element-type-changing transformations return the concrete type.
429437
| `sort` / `sortBy` / `sortByDescending` / `sortDescending` / `sortWith` | | ✓ | – | – | – | – | – | – | Sorting, unstable like `Array.Parallel.sort*`; `sortInPlace*` omitted |
430438

431439
`Option.*`: `choose`, `pick`, `tryExactlyOne`, `tryFind`, `tryFindBack`, `tryFindIndex`, `tryFindIndexBack`, `tryHead`,
432-
`tryItem`, `tryLast`, `tryPick`, `tryTail`, `tryUncons`, `unfold`.
440+
`tryItem`, `tryLast`, `tryPick`, `tryTail`, `tryUncons`, `unfold`, `(|Cons|_|)`.
433441
`Tuple.*`: `allPairs`, `countBy`, `groupBy`, `indexed`, `mapFold`, `mapFoldBack`, `pairwise`, `partition`, `partitionWith`,
434-
`splitAt`, `unfold`, `unzip`, `unzip3`, `zip`, `zip3`, `uncons`, `tryUncons`, `(|Cons|Nil|)` where present.
442+
`splitAt`, `unfold`, `unzip`, `unzip3`, `zip`, `zip3`, `uncons`, `tryUncons`, `(|Cons|_|)` where present.
443+
444+
`EquatableArray<'T>` of ADR 0002 mirrors the `FlatList` column, without `isDefault` and `isDefaultOrEmpty`, and adds
445+
`ofImmutableArray`, `toImmutableArray` and `unsafeOfArray`.
435446

436447
## Appendix B – maps
437448

0 commit comments

Comments
 (0)