Skip to content

[CPyCppyy] Remove pointer-based fallback in CPPInstance equality check - #21572

Draft
guitargeek wants to merge 1 commit into
root-project:masterfrom
guitargeek:issue-21347
Draft

[CPyCppyy] Remove pointer-based fallback in CPPInstance equality check#21572
guitargeek wants to merge 1 commit into
root-project:masterfrom
guitargeek:issue-21347

Conversation

@guitargeek

Copy link
Copy Markdown
Contributor

The Python proxy for C++ objects previously implemented a fallback equality comparison based on proxy type and the held C++ pointer address when no C++ operator== / operator!= was available. This behavior was misleading, because it made expressions like a == b appear to perform a value comparison even though no corresponding C++ operator was defined.

This patch removes the implicit pointer-based fallback and instead raises a TypeError when equality is requested between two CPPInstance proxies for which no C++ equality operator can be resolved. This avoids silently changing semantics and makes unsupported comparisons explicit.

The only case where the pointer-based fallback is kept is for proxies of the exact same type when at least one wraps a nullptr: in this case, comparison continues to be performed on the pointer value, because comparing by value would not be possible. This preserves existing cppyy behavior in a case that is not semantically ambiguous. Although C++ would also allow comparisons between nullptr pointers of types related by inheritance, broadening the rule would silently change previous cppyy behavior, where such comparisons returned False.

To summarize: this change prevents ambiguous equality semantics while avoiding silent behavior changes for existing code by raising a type error in cases that are ambiguous or where previous behavior was different from C++ semantics.

Closes #21347.

@vepadulano vepadulano left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not against the change per se, but this needs a very explicit mention in the release notes as well as a paragraph or two in the Pythonization section of the docs.

Comment on lines +609 to +611
"\n\nThe Python proxy no longer falls back to comparing by type and held C++ pointer "
"address, because that can be misleading: using `%s` may look like a value comparison "
"even though no corresponding C++ operator is available."

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This wording will age very quickly, I would rephrase in such a way to just indicate the reason for the failure and provide the user with suggestions on what to do (e.g. implent a custom __eq__ for their own classes where it makes sense).

@guitargeek

Copy link
Copy Markdown
Contributor Author

Thanks for the early review! Good to know that you are not opposed to this change. But before writing the release notes, I still have some test failures to figure out, so I'll mark this PR as draft for now

@guitargeek
guitargeek marked this pull request as draft March 11, 2026 13:58
@github-actions

github-actions Bot commented Mar 11, 2026

Copy link
Copy Markdown

Test Results

    23 files      23 suites   5d 3h 39m 15s ⏱️
 3 854 tests  3 847 ✅ 0 💤  7 ❌
79 426 runs  79 331 ✅ 0 💤 95 ❌

For more details on these failures, see this check.

Results for commit 8a75fcb.

♻️ This comment has been updated with latest results.

The Python proxy for C++ objects previously implemented a fallback equality
comparison based on proxy type and the held C++ pointer address when no
C++ `operator==` / `operator!=` was available. This behavior was
misleading, because it made expressions like `a == b` appear to perform
a value comparison even though no corresponding C++ operator was
defined.

This patch removes the implicit pointer-based fallback and instead raises
a TypeError when equality is requested between two CPPInstance proxies for
which no C++ equality operator can be resolved. This avoids silently
changing semantics and makes unsupported comparisons explicit. The error
message states why the comparison is not supported and what to do instead:
define a C++ `operator==` for the operands, implement `__eq__` and `__ne__`
from Python, or compare the addresses of the wrapped C++ objects explicitly
with `cppyy.addressof()`.

The only case where the pointer-based fallback is kept is for proxies of
the exact same type when at least one wraps a `nullptr`: in this case,
comparison continues to be performed on the pointer value, because
comparing by value would not be possible. This preserves existing cppyy
behavior in a case that is not semantically ambiguous. Although C++
would also allow comparisons between nullptr pointers of types related
by inheritance, broadening the rule would silently change previous cppyy
behavior, where such comparisons returned `False`.

To summarize: this change prevents ambiguous equality semantics while
avoiding silent behavior changes for existing code by raising a type
error in cases that are ambiguous or where previous behavior was
different from C++ semantics.

Since this is a change in behavior that user code can rely on, it is
announced in the ROOT 6.42 release notes, and the new semantics are
explained in the "Equality comparisons" section of the pythonizations
documentation.

Closes root-project#21347.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Python] Change of behavior in TObject equality comparisons

2 participants