Skip to content

Do not create attributes as a side effect of reading them#17

Merged
gitosaurus merged 3 commits into
mainfrom
fix/attribute-read-no-mutation
Apr 18, 2026
Merged

Do not create attributes as a side effect of reading them#17
gitosaurus merged 3 commits into
mainfrom
fix/attribute-read-no-mutation

Conversation

@gitosaurus
Copy link
Copy Markdown
Owner

AttributeValue::dereference_() was calling setAttribute() to stamp an UNDEFINED value onto an object whenever a nonexistent attribute was read. This caused phantom attributes to accumulate over time, inflating save files and polluting the object model. Instead, return UNDEFINED directly without mutation — hasAttribute() already walks the parent chain for inherited lookups.

The setAttribute call was introduced in 4fdcb62 (2014) to make the getAttributeValue() path uniform, but returning early for the not-found case is simpler and avoids the side effect.

AttributeValue::dereference_() was calling setAttribute() to stamp an
UNDEFINED value onto an object whenever a nonexistent attribute was
read. This caused phantom attributes to accumulate over time, inflating
save files and polluting the object model. Instead, return UNDEFINED
directly without mutation — hasAttribute() already walks the parent
chain for inherited lookups.

The setAttribute call was introduced in 4fdcb62 (2014) to make the
getAttributeValue() path uniform, but returning early for the
not-found case is simpler and avoids the side effect.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Copy link
Copy Markdown

Copilot AI left a comment

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 removes a long-standing side effect where reading a missing object attribute would implicitly create and persist an UNDEFINED attribute entry, leading to “phantom” attributes and inflated save data.

Changes:

  • Updates AttributeValue::dereference_() to return UNDEFINED immediately when the target object is missing or the attribute is not present, without mutating the object.
  • Eliminates the previous setAttribute(..., UNDEFINED) stamping behavior on attribute reads.

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

Comment thread src/Value.cc
Comment thread src/Value.cc
gitosaurus and others added 2 commits April 18, 2026 13:41
Distinguishes locally-set attributes from inherited ones — useful for
SITREP-style introspection and as a regression guard. The extended test
asserts that reading an inherited attribute returns the parent's value
without creating a local entry on the child.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@gitosaurus gitosaurus merged commit 5a2aaee into main Apr 18, 2026
1 check passed
@gitosaurus gitosaurus deleted the fix/attribute-read-no-mutation branch April 18, 2026 20:46
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