Skip to content

[REFACTOR][EXTRA] Add StructuralMutate, a callback-driven mutation primitive - #751

Merged
tqchen merged 2 commits into
apache:mainfrom
tqchen:claude-nv8180/structural-mutate
Sep 6, 2026
Merged

[REFACTOR][EXTRA] Add StructuralMutate, a callback-driven mutation primitive#751
tqchen merged 2 commits into
apache:mainfrom
tqchen:claude-nv8180/structural-mutate

Conversation

@tqchen

@tqchen tqchen commented Sep 5, 2026

Copy link
Copy Markdown
Member

Structural mutation needs a callback-owned form where a matched callback decides whether and how to recurse, and its replacement remains final.

This adds StructuralMutate and StructuralMutateExpected with declaration-ordered typed and runtime dispatch. Both engines preserve distinct ordinary and maybe-in-place fallbacks, use the exact Parent::MutatorObjType callback view, and let matched variable callbacks own remap consistency.

Map and mutate entry points now take the root as Any by value, so in-place reuse requires explicit ownership transfer with std::move or Python _move(). Existing StructuralMap callers therefore lose opportunistic in-place reuse until they move an owned root. StructuralMutate callbacks may optionally take allow_inplace as a third argument; two-argument callbacks retain the copy-on-write default.

Object metadata can now promise that subclasses retain one structural equality/hash kind. Registration rejects violations, and mutation skips runtime remap metadata lookup for final or kind-fixed non-remappable callback types.

The runtime and Python interfaces expose callback dispatch and default_mutate but intentionally omit a direct Python maybe-in-place mutator method. Shared-subvalue, moved-root identity, nested-hook ownership, callback-path, and paired visit/mutate recursion tests keep the interfaces aligned.

Validation: all 493 C++ tests and all 2,495 Python tests pass; the generated FFI stub and full pre-commit suite, including ty, clang-format, and CMake lint/format, are clean.

@tqchen
tqchen force-pushed the claude-nv8180/structural-mutate branch 12 times, most recently from 1117138 to 8b6e273 Compare September 6, 2026 02:14
StructuralMap cannot treat a callback replacement as final because it
owns recursive descent. StructuralMutate lets the first matching
callback own mutation and explicitly choose recursion through the
handed mutator.

Add the typed C++ engine and Expected/throwing entry points. Take map
and mutate roots by value so explicit ownership transfer governs
in-place reuse, and expose the active path through an optional callback
flag. Add runtime and Python dispatch plus focused behavior tests.
@tqchen
tqchen force-pushed the claude-nv8180/structural-mutate branch from 8b6e273 to a7d7076 Compare September 6, 2026 02:46
@tqchen
tqchen merged commit 6b1b19d into apache:main Sep 6, 2026
9 checks passed
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