[Bugfix] .parent allocates a fresh wrapper on every read, so child.parent is parent is always False #369
Labels
No labels
Alpha Release Requirement
Bugfix
Demo Target
Documentation
Major Feature
Minor Feature
priority:tier1-active
priority:tier2-foundation
priority:tier3-future
priority:tier4-deferred
Refactoring & Cleanup
system:animation
system:documentation
system:grid
system:input
system:performance
system:procgen
system:python-binding
system:rendering
system:ui-hierarchy
Tiny Feature
workflow:blocked
workflow:needs-benchmark
workflow:needs-documentation
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
john/McRogueFace#369
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Found while writing #364's tests. Affects every drawable type, not just grids.
Defect
UIDrawable::get_parent(src/UIDrawable.cpp:1280) builds a brand-new Python wrapper on each access -- every arm of its switch is a baretype->tp_alloc(...)with noPythonObjectCachelookup:So object identity never holds:
The wrappers do share the underlying
shared_ptr, so mutation through either one works. It is identity, not behavior, that is broken -- butisis exactly what a user writes to ask "am I inside this frame?", and it silently answers no.Consequences
child.parent is some_frameis unusable; users must compare.nameor another observable instead.Frame/Gridsubclass reached through.parentcomes back as the base type, losing the Python subclass identity that #266 established forEntity(UIEntity::pyobject). Any state a user put on their subclass instance is invisible through.parent.id(x.parent)is unstable across reads, so.parentcannot be used as a dict key or in aset.Fix
Route every arm through
PythonObjectCache(keyed onserial_number) the way the entity path does, returning the existing wrapper when one is alive and only allocating on a miss.RET_PY_INSTANCEalready switches onderived_type()to build the right wrapper -- the cache lookup belongs alongside it so.parent, collection indexing, andfind()all return the same object for the same C++ drawable.Worth auditing the sibling paths in the same pass:
UICollectionindexing/iteration andmcrfpy.find()may have the same gap, in which casescene.children[0] is scene.children[0]is also False.Test
tests/regression/issue_364_grid_children_on_view_test.pycurrently assertsbubble.parent.name == "the_view"with a comment explaining whyiscannot be used. When this is fixed, tighten that tobubble.parent is gridand add a subclass round-trip:class MyGrid(mcrfpy.Grid), append a child, assertchild.parentis theMyGridinstance and retains its Python attributes.