Skip to content

Commit 10b17c5

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 8136bd9 commit 10b17c5

1 file changed

Lines changed: 20 additions & 10 deletions

File tree

‎docsSrc/Explanations/ADR_0001_Collection_Modules.md‎

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -50,11 +50,13 @@ 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`
59+
`cons`/`uncons`/`tryUncons`, the struct partial patterns `(|Cons|_|)`/`(|Nil|_|)`, `tryTail`, `enqueue`/`enqueueMany`, `consMany`, `takeLast`/`skipLast`, `clear`
5860
on interface modules, `tryGetKey`/`tryGetValue`, `setItem`/`setItems`/`addRange`/`removeRange`, `containsValue`,
5961
`symmetricDifference`, `overlaps`/`setEquals`, comparer accessors and `with*Comparer` functions.
6062

@@ -76,7 +78,7 @@ Names: `IMap` module and `IMap<'Key, 'Value>` abbreviation for `IImmutableDictio
7678
Maps and sets measure their size with `count` (FSharp.Core `Map.count`/`Set.count`), sequences with `length`. `Queue` keeps
7779
`enqueue`/`head`/`tail`/`uncons` (compiled `Enqueue`/`Peek`/`Dequeue`/`PeekDequeue`), `Stack` keeps `cons`/`head`/`tail`/
7880
`uncons` (`Push`/`Peek`/`Pop`/`PeekPop`). Computation expression instances: `flatList`, `indexedList`, `queue`, `stack`,
79-
`hashMap`, `sortedMap`, `hashSet`, `sortedSet`, `frozenMap`, `frozenSet`.
81+
`hashMap`, `sortedMap`, `hashSet`, `sortedSet`, `frozenMap`, `frozenSet`, and `equatableArray` of ADR 0002.
8082

8183
### D3. Value-type defaults and the `Option`/`Tuple` override namespaces
8284

@@ -147,8 +149,9 @@ FSharp.Core module that a collection mirrors: `FlatList` and `FlatList.Parallel`
147149
`Array.Parallel.sort*` are documented ("This is not a stable sort"), through `ImmutableArray.Sort` or `Array.sort*` on the
148150
bridge; `IndexedList`, `Queue`, `Stack` and their interface modules sort stably, as `List.sort*` and `Seq.sort*` are
149151
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.
152+
Every sort compares in the order of F# generic comparison (`LanguagePrimitives.FastGenericComparer<'T>`, the comparer
153+
behind `compare`), never with a culture-sensitive comparer such as `Comparer<string>.Default`. ADR 0002 §3 shows the
154+
effect on strings and uses the same order for the elements of `EquatableArray`.
152155

153156
Consequences for the types: `FlatList` range operations (`take`, `skip`, `truncate`, `splitAt`, `takeLast`, `skipLast`,
154157
`chunkBySize`, `windowed`) copy the selected elements. An `ImmutableArray` is a single array reference without an offset or a
@@ -190,18 +193,21 @@ which sorts unstably, see D5); `Map`, `MapTransform`, `MapMutation`, `MapCreatio
190193
observed enumeration order, so one test body serves FIFO, LIFO and indexed collections. Collection-specific behaviour
191194
(`isDefault`, spans, builders, `Stack.cons` direction, comparers, sorted-only functions, null inputs) lives in a per-collection
192195
file. Exceptions are asserted with `Assert.ThrowsExactly` on type, `ParamName` and message prefix; every assertion carries
193-
a message; categories come from `TestCategories.fs` attributes (collection level) and `TestCategory` strings or `nameof`
194-
(operation level). Dedicated files per collection prove that opening the `Option`/`Tuple` namespaces shadows the default
196+
a message; categories come from `TestCategories.fs` attributes (collection level) and `TestCategory (nameof …)`
197+
(operation level), never from string literals. In a contract base, the function of any module gives the name, for
198+
example `nameof FlatList.map`. Dedicated files per collection prove that opening the `Option`/`Tuple` namespaces shadows the default
195199
functions and that the override functions are equivalent to the defaults after conversion.
196200

197201
### D9. Delivery: one pull request per collection, stacked
198202

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

206212
### D10. Target frameworks
207213

@@ -317,7 +323,8 @@ their element-type-changing transformations return the concrete type.
317323
| `tryTail` | Ⓥ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | |
318324
| `tryUncons` | Ⓥ+Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | `struct ('T * X<'T>) voption` |
319325
| `uncons` | Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | compiled `PeekDequeue`/`PeekPop` |
320-
| `(\|Cons\|Nil\|)` | Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | |
326+
| `(\|Cons\|_\|)` | Ⓥ+Ⓣ | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | `[<return: Struct>]`, `struct ('T * X<'T>) voption`; a multi-case pattern allocates a `Choice` per match (ADR 0002 §5) |
327+
| `(\|Nil\|_\|)` | | – | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | ᵃ | returns `bool` |
321328
| **Search** | | | | | | | | | |
322329
| `binarySearch` | | ᵇ | ᵇ | – | – | – | – | – | BCL bitwise-complement contract |
323330
| `contains` | | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | ✓ | |
@@ -395,9 +402,12 @@ their element-type-changing transformations return the concrete type.
395402
| `sort` / `sortBy` / `sortByDescending` / `sortDescending` / `sortWith` | | ✓ | – | – | – | – | – | – | Sorting, unstable like `Array.Parallel.sort*`; `sortInPlace*` omitted |
396403

397404
`Option.*`: `choose`, `pick`, `tryExactlyOne`, `tryFind`, `tryFindBack`, `tryFindIndex`, `tryFindIndexBack`, `tryHead`,
398-
`tryItem`, `tryLast`, `tryPick`, `tryTail`, `tryUncons`, `unfold`.
405+
`tryItem`, `tryLast`, `tryPick`, `tryTail`, `tryUncons`, `unfold`, `(|Cons|_|)`.
399406
`Tuple.*`: `allPairs`, `countBy`, `groupBy`, `indexed`, `mapFold`, `mapFoldBack`, `pairwise`, `partition`, `partitionWith`,
400-
`splitAt`, `unfold`, `unzip`, `unzip3`, `zip`, `zip3`, `uncons`, `tryUncons`, `(|Cons|Nil|)` where present.
407+
`splitAt`, `unfold`, `unzip`, `unzip3`, `zip`, `zip3`, `uncons`, `tryUncons`, `(|Cons|_|)` where present.
408+
409+
`EquatableArray<'T>` of ADR 0002 mirrors the `FlatList` column, without `isDefault` and `isDefaultOrEmpty`, and adds
410+
`ofImmutableArray`, `toImmutableArray` and `unsafeOfArray`.
401411

402412
## Appendix B – maps
403413

0 commit comments

Comments
 (0)