[REFACTOR][EXTRA] Add StructuralMutate, a callback-driven mutation primitive - #751
Merged
Merged
Conversation
tlopex
approved these changes
Sep 5, 2026
tqchen
force-pushed
the
claude-nv8180/structural-mutate
branch
12 times, most recently
from
September 6, 2026 02:14
1117138 to
8b6e273
Compare
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
force-pushed
the
claude-nv8180/structural-mutate
branch
from
September 6, 2026 02:46
8b6e273 to
a7d7076
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
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.