Skip to content

Micro pass over the diff hot paths: skip-equal keys, shared pointers, exact-class dispatch#56

Merged
Korijn merged 1 commit into
masterfrom
claude/diff-micro
Jul 11, 2026
Merged

Micro pass over the diff hot paths: skip-equal keys, shared pointers, exact-class dispatch#56
Korijn merged 1 commit into
masterfrom
claude/diff-micro

Conversation

@Korijn

@Korijn Korijn commented Jul 11, 2026

Copy link
Copy Markdown
Collaborator

Track E, PR 11 — the diff/pointer micro pass. Rebased onto master now that #53 (Myers) and #52 (typecheck fix) are merged — this diff is now just the micro-pass commit on its own.

What

  • diff_dicts: compare common-key values before recursing. Equal values used to pay a diff() call plus a child Pointer allocation just to return an empty result — which was most of the work when few of many common keys changed. Changed values now pay one extra fail-fast compare instead.
  • diff_sets: one shared - pointer for all add operations (pointers are immutable, so sharing is safe) instead of allocating one per element, plus a bound ptr.append for removes.
  • diff(): exact-class dispatch first with an atomic-type short-circuit; the hasattr chain stays as the fallback for container look-alikes such as observ proxies. Scalar replace leaves no longer pay up to six hasattr calls.

Benchmarks

Interleaved medians vs the Myers branch, 2 runs each:

benchmark before after change
dict_diff_flat_500_keys 243.5µs 86.7µs −64.5%
set_diff_1000_elements 70.9µs 49.3µs −31.0%
mixed_dict_with_list_values 123.3ms 124.6ms −8.1%
dict_diff_large_common[500/1000/2000] +0.9…+1.9%
dict_diff_nested 31.9µs 33.1µs +3.8%
pointer benchmarks unchanged

The small upticks are the honest cost of the skip-equal pre-check on workloads where every common key changed (the pre-check never skips, and diff() re-compares) — a few percent against −64% when keys are mostly unchanged, which is the common real-world shape.

Negative result, documented: an indexing rewrite of Pointer.evaluate (avoiding the tokens[:-1] slice copy) benchmarked 18–26% slower — tuple-slice iteration beats indexed access in CPython — and was rejected; pointer.py is untouched by this PR.

407 tests at 100% coverage, ruff and ty clean.

🤖 Generated with Claude Code

https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2

@Korijn Korijn force-pushed the claude/diff-micro branch 2 times, most recently from 7f46ac8 to 271b3d3 Compare July 11, 2026 08:32
@Korijn Korijn force-pushed the claude/myers-diff branch from ddbf849 to 4aba07c Compare July 11, 2026 08:35
@Korijn Korijn force-pushed the claude/diff-micro branch from 271b3d3 to 6a60c03 Compare July 11, 2026 08:35
Base automatically changed from claude/myers-diff to master July 11, 2026 10:46
… exact-class dispatch

- diff_dicts: compare common-key values before recursing - equal values
  used to pay a diff() call plus a child Pointer allocation just to
  return an empty result, which was most of the work when few of many
  common keys changed; changed values now pay one extra (fail-fast)
  compare instead
- diff_sets: one shared "-" pointer for all add operations (pointers
  are immutable) instead of allocating one per element, and a bound
  ptr.append for the removes
- diff(): dispatch on exact classes first with an atomic-type
  short-circuit, keeping the hasattr chain as the fallback for
  container look-alikes such as observ proxies; scalar replace leaves
  no longer pay up to six hasattr calls

Interleaved benchmark medians vs the Myers branch (2 runs each):

  dict_diff_flat_500_keys   243.5us -> 86.7us  (-64.5%)
  set_diff_1000_elements    70.9us  -> 49.3us  (-31.0%)
  mixed_dict_with_lists     123.3ms -> 124.6ms (-8.1% on mean medians)
  dict_diff_large_common    +0.9..+1.9% (every common key changed, so
                            the pre-check never skips; fail-fast cost)
  dict_diff_nested          +3.8% (same, on nested values)
  pointer benchmarks        unchanged

An indexing rewrite of Pointer.evaluate was tried and rejected: it
benchmarked 18-26% slower than iterating the tokens[:-1] slice.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016Mu9vEBwU4fQLi8ZgkgdS2
@Korijn Korijn force-pushed the claude/diff-micro branch from 6a60c03 to 1d60335 Compare July 11, 2026 10:55
@Korijn Korijn merged commit aef2715 into master Jul 11, 2026
11 checks passed
@Korijn Korijn deleted the claude/diff-micro branch July 11, 2026 11:00
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