Skip to content

feat: Locked/LockedOrdered delegate all optional optimization interfaces #minor - #44

Merged
freeformz merged 1 commit into
mainfrom
locked-delegation
Jul 13, 2026
Merged

feat: Locked/LockedOrdered delegate all optional optimization interfaces #minor#44
freeformz merged 1 commit into
mainfrom
locked-delegation

Conversation

@freeformz

Copy link
Copy Markdown
Owner

Summary

Third item from the optional-interface survey (follow-up to #42/#43): wrapping a set in Locked or LockedOrdered no longer silently discards its fast paths. Both wrappers now implement all nine optional interfaces — Unioner/Intersectioner/Differencer/SymmetricDifferencer, Equaler/Disjointer/Subsetter, and Maxer/Minner — by delegating to the inner set under the read lock, declining to the generic path when the inner set doesn't implement or declines the hook.

Deadlock safety

Delegation may need two locks (receiver + a locked operand), and two goroutines running mirror-image operations on the same pair is the classic deadlock shape. The rule: the receiver's own lock is acquired normally, but a locked operand is unwrapped with a non-blocking TryRLock — under contention the delegation declines, and the package-level function falls back to the generic path, which locks one set at a time. The declining-boolean contract absorbs contention the same way it absorbs type mismatches: worst outcome is generic speed, never a wrong result or a deadlock. A -race stress test runs both operand orders concurrently against writers to pin this.

Notes

  • Delegated set-algebra results come back wrapped (Locked/LockedOrdered), staying concurrency-safe and keeping the package functions' same-underlying-type-as-a contract
  • Locked's element type is only comparable, so its Max/Min match the inner set structurally (interface{ Max() (M, bool) }); instantiated with an ordered element type, Locked satisfies Maxer/Minner (compile-time asserted)
  • Typed-nil and zero-value (nil inner) wrappers decline as both receivers and operands — the nil-safety class from feat: SortedSet merge-based set algebra and Maxer/Minner fast paths #minor #42, handled up front
  • Cross-wrapper delegation works: Locked(BitSet) × LockedOrdered(BitSet) still hits the word-wise fast path

Testing

  • TestLockedDelegation: rapid differential test against Map-based generic results across seven operand pairings — wrapped×wrapped, wrapped×bare, cross-wrapper, and declining combinations (mismatched inner types, non-optimizable Map inner) — for all four algebra ops, all four predicates, and Max/Min; algebra results asserted to be Lockers
  • TestLockedDelegationResultTypes: pins the wrapper/inner types of delegated results and method-level declines
  • TestLockedDelegationContention: deterministic decline while the operand is write-locked (and recovery after unlock; self-operand delegation)
  • TestLockedDelegationNilAndZero: typed-nil and zero-value pins
  • stresstest.TestLockedDelegationConcurrency: 4 readers in mirror-image operand orders + 2 writers under -race — terminates (no deadlock) and race-clean
  • go vet, staticcheck, and go test -race ./... all clean

🤖 Generated with Claude Code

https://claude.ai/code/session_01RLrWSEKLMPuf1kq1KDCoxs

…ces #minor

Wrapping a set in Locked or LockedOrdered no longer loses its fast paths: both
wrappers now implement Unioner, Intersectioner, Differencer,
SymmetricDifferencer, Equaler, Disjointer, Subsetter, Maxer, and Minner by
delegating to the inner set under the read lock, declining to the generic path
when the inner set doesn't implement or declines the hook.

Deadlock safety: the receiver's own lock is acquired normally, but a locked
operand is unwrapped with a non-blocking TryRLock — under contention the
delegation declines and the package-level function falls back to the generic
path, which locks one set at a time. Mirror-image concurrent operations on the
same pair of locked sets therefore cannot deadlock (pinned by a stress test).

- delegated set-algebra results come back wrapped (Locked / LockedOrdered), so
  they stay concurrency-safe and keep the same-underlying-type contract
- Locked's element type is only comparable, so its Max/Min match the inner set
  structurally; instantiated with an ordered type it satisfies Maxer/Minner
- typed-nil and zero-value (nil inner) wrappers decline as both receivers and
  operands
- rapid differential tests over wrapped×wrapped, wrapped×bare, cross-wrapper,
  and declining inner-type combinations; result-type pins; deterministic
  contention-decline test; nil/zero pins; -race stress test running both
  operand orders against concurrent writers

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01RLrWSEKLMPuf1kq1KDCoxs
Copilot AI review requested due to automatic review settings July 13, 2026 20:05

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR updates the Locked and LockedOrdered wrappers so they no longer drop optional optimization fast paths (set-algebra, predicates, and Max/Min) when wrapping an optimizable inner set. The wrappers now implement the optional interfaces by delegating to the inner set under a read lock, using TryRLock when unwrapping a locked operand to avoid deadlock and decline into the generic one-lock-at-a-time fallback under contention.

Changes:

  • Implement optional interface delegation for Locked and LockedOrdered, including deadlock-safe operand unwrapping via non-blocking read locks.
  • Add comprehensive tests (property-based + contention + race/deadlock stress) to validate correctness, result types, and concurrency safety.
  • Update documentation (godoc, README, CLAUDE.md) to describe the delegation behavior and deadlock-avoidance rule.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated no comments.

Show a summary per file
File Description
stresstest/locked_delegate_stress_test.go Adds a -race-oriented concurrency stress test to validate no-deadlock behavior under mirrored operand orders and concurrent writers.
set.go Updates set-algebra optional-interface documentation to note locked-wrapper delegation preserves fast paths.
README.MD Documents locked-wrapper delegation, contention decline behavior, and wrapped results.
locked.go Implements delegation for all optional optimization interfaces (algebra, predicates, Max/Min) with deadlock-safe operand unwrapping.
locked_ordered.go Mirrors the delegation behavior for LockedOrdered, ensuring ordered results remain ordered and safely wrapped.
locked_delegate_test.go Adds targeted tests covering delegation correctness, result wrapper types, contention declines, and nil/zero-value decline behavior.
CLAUDE.md Updates repository documentation to reflect locked-wrapper optional-interface delegation and deadlock safety.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@freeformz
freeformz merged commit a062710 into main Jul 13, 2026
11 checks passed
@freeformz
freeformz deleted the locked-delegation branch July 13, 2026 20:13
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