Skip to content

refactor(dummies): share the collection count facade across generators#285

Merged
Reefact merged 1 commit into
mainfrom
claude/issue-225-discussion-k43t3v
Jul 22, 2026
Merged

refactor(dummies): share the collection count facade across generators#285
Reefact merged 1 commit into
mainfrom
claude/issue-225-discussion-k43t3v

Conversation

@Reefact

@Reefact Reefact commented Jul 22, 2026

Copy link
Copy Markdown
Owner

Summary

AnyDictionary re-implemented the entire collection count facade — NonEmpty/Empty/WithCount/WithMinCount/WithMaxCount/WithCountBetween plus the RequireNonNegative/V helpers — verbatim from AnyCollection, so any fix or message change to the count algebra had to be mirrored by hand and could silently drift between the two surfaces. This extracts that logic once into an internal helper both surfaces delegate to. No behaviour change.

This is change 1 of the two independent changes described in #225 (the shared count facade); the containment surface (ContainingKey) is left for a follow-up.

Type of change

  • Bug fix
  • New feature
  • Breaking change
  • Refactoring
  • Analyzer / diagnostic change
  • Tests
  • Documentation
  • Build / CI / tooling

Changes

  • Add Dummies/CountConstraints.cs: an internal static helper defining the six count operations once over CollectionState<T>, carrying the argument validation and the constraint labels that surface in ConflictingAnyConstraintException.
  • AnyCollection<TItem, TResult, TSelf> (list, array, sequence, set) now delegates its count methods to CountConstraints and drops its private RequireNonNegative/V helpers.
  • AnyDictionary<TKey, TValue> delegates its key-count methods to the same helper, removing the ~60-line verbatim copy.
  • Public API is unchanged: signatures, exception types and parameter names, and the constraint label strings are all preserved (the PublicAPI.*.txt baselines are untouched). Labels stay produced in the facade rather than in the label-agnostic CollectionState.

Testing

  • dotnet build FirstClassErrors.sln — Build succeeded, 0 Warning(s), 0 Error(s) (both the netstandard2.0 and net8.0 legs of Dummies compiled).
  • dotnet test FirstClassErrors.sln — full suite not run locally; ran dotnet test Dummies.UnitTests instead: 448 passed, 0 failed, 0 skipped.
  • Analyzer tests pass (FirstClassErrors.Analyzers.UnitTests) — not run; no analyzer change in this PR.

Documentation

  • Public API / error documentation updated
  • README / doc/ updated
  • French translation (doc/handwritten/for-users/README.fr.md) updated if user-facing behavior changed
  • No documentation change required — internal refactor, no user-facing behaviour and no public API change.

Architecture decisions

  • No architectural decision in this pull request — internal deduplication only. It is consistent with the existing collection-generator design (ADR-0011 standalone Dummies, ADR-0013 cardinality gating, ADR-0020 materialize-through-Generate) and changes none of them.
  • New decision recorded — ADR drafted as Proposed: ADR-____
  • Supersedes an existing ADR — successor proposed, status not flipped: ADR-____
  • ⚠️ Conflicts with an existing ADR — flagged for the maintainer: ADR-____

Related issues

Refs #225 (does not close it — the ContainingKey change from the same issue is a separate follow-up).


Generated by Claude Code

AnyDictionary re-implemented the entire count facade — NonEmpty, Empty,
WithCount, WithMinCount, WithMaxCount, WithCountBetween plus the
RequireNonNegative/V helpers — verbatim from AnyCollection, so any fix or
message change to the count algebra had to be mirrored by hand and could
silently drift between the two surfaces.

Extract that logic once into an internal CountConstraints helper over
CollectionState: each generator now delegates its count methods to the
helper and wraps the returned state in its own immutable type. The
AnyCollection builders (list, array, sequence, set) and AnyDictionary now
share a single definition.

Behaviour is unchanged: public signatures, exception types and parameter
names, and the constraint labels that surface in conflict messages are all
preserved, and the labels stay out of the label-agnostic CollectionState.

Refs: #225

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018RduXUaM3V6tk6MuKxzVzJ
@Reefact
Reefact merged commit 7d37450 into main Jul 22, 2026
16 checks passed
@Reefact
Reefact deleted the claude/issue-225-discussion-k43t3v branch July 22, 2026 09:38
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