Skip to content

smart_holder fixups #3012

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
May 28, 2021
Merged

smart_holder fixups #3012

merged 4 commits into from
May 28, 2021

Conversation

rhaschke
Copy link
Contributor

These are some fixups for the smart_holder branch. See individual commit messages for details. @rwgk

std::shared_ptrs can be shared across python and C++ by design.
rhaschke added 2 commits May 20, 2021 22:53
It is important to return an empty handle.
Simply returning None, would skip the error handling in
simple_collector / unpacking_collector, although a python exception is set.
A function call would then be processed with a (wrong) None argument!
@rhaschke rhaschke marked this pull request as ready for review May 20, 2021 21:21
@rhaschke
Copy link
Contributor Author

@rwgk, given that you have forbidden passing of a std::shared_ptr from C++ to Python before, I guess you also don't yet have roundtrip tests for that use case, i.e. C++ -> Python -> C++ and Python -> C++ -> Python.

@rwgk
Copy link
Collaborator

rwgk commented May 21, 2021

@rwgk, given that you have forbidden passing of a std::shared_ptr from C++ to Python before,

Do you mean "forbidden passing ... for return value policies other than automatic and reference_internal"? What other return value policies are important to support? My thinking was that it's important to throw an exception for the ones that really don't fit the situation, e.g. take_ownership really doesn't make sense in any way I can think of. Similarly, what's the desired semantics of reference, move, or copy? If we accept all those policies without doing anything different or throwing an exception, it's likely misunderstandings or oversights go unnoticed until (much) later (when it can be very costly to debug).

I guess you also don't yet have roundtrip tests for that use case, i.e. C++ -> Python -> C++ and Python -> C++ -> Python.

test_class_sh_basic exercises std::shared_ptr returns and passing, but I'm sure you saw that. I didn't think a round trip test like we have for std::unique_ptr is needed, since there isn't anything tricky.

@rhaschke
Copy link
Contributor Author

Sorry, obviously it was too late yesterday evening when I wrote this: I neglected that you did handle the cases of automatic and reference_internal. I was particularly missing automatic_reference, which is the default for (C++) arguments passed to python functions from C++.
Regarding copy and move: these are the actual policies automatic would resolve to for non-holder values. For this reason, these two should be definitely supported. Also, if you support reference_internal, you should support reference as well. They don't differ in the handling of the argument itself, but only in the life-time handling of its parent.
I agree that take_ownership doesn't really make sense for a shared pointer. On the other side, it doesn't harm to allow this policy and handle it just like all others. It would be the only one throwing an exception. Allowing it too, we can skip the test completely.

@rwgk
Copy link
Collaborator

rwgk commented May 21, 2021

I just re-read the documentation for the return value policies. The documentation for reference explicitly mentions "do not take ownership", which in the context of shared_ptr is unclear/weird. For copy and move I still feel strongly that those are also best not allowed to avoid guessing and confusion about what they may do. I could be convinced otherwise if those restrictions generate burdensome situations elsewhere, but at the moment I'm thinking simply guiding people to not specify a return value policy that doesn't make a difference anyway is the right thing to do.

If someone really wants to copy or move a value pointed at by a shared_ptr, they can do that easily via a lambda, dereferencing the shared_ptr. Then it's clear and obvious in the bindings code that something unusual is happening, and that it's not different from the behavior for a raw pointer return.

The other changes look good. If you put back the return value policy test I'll merge this PR (after also testing google-internally). We could continue the return value policy discussion separately if needed.

@rhaschke
Copy link
Contributor Author

@rwgk, I readded the policy check. But I still don't agree with you that copy or move should be rejected.
I see your point that the semantics is not very clear for a shared_ptr.
On the other hand, the return value policy doesn't actually matter for a shared_ptr. So, why would you restrict the allowed values?

@rwgk
Copy link
Collaborator

rwgk commented May 28, 2021

Thanks for the fixes! I'll merge this now.

So, why would you restrict the allowed values?

The main reason is to not lead people into "what does this do?" guessing. Some will just always harbor doubts but never look. That's just wasting a few cognitive cycles. Others (most?) will just copy-paste what they see without understanding. At large scale (our code base has 100s of millions of lines) that copy-paste clutter has a tendency to turn into life-consuming cleanup jobs, when at some point later, it is found that e.g. copy or move actually can have useful semantics. Then those previously meaningless policies scattered around the code base need to be identified and removed. — Coincidentally, I just spent more than a week on something like that. I want to do everything I can to weed out the potential for such a waste of time right at the root.

@rwgk rwgk merged commit 91f97ca into pybind:smart_holder May 28, 2021
@github-actions github-actions bot added the needs changelog Possibly needs a changelog entry label May 28, 2021
@rwgk rwgk removed the needs changelog Possibly needs a changelog entry label May 28, 2021
@rhaschke rhaschke deleted the sh-fixups branch May 28, 2021 14:36
@jakobandersen
Copy link
Contributor

This fixed my original issue in #3011. However, the second issue (#3011 (comment)) still gives the error RuntimeError: Invalid return_value_policy for shared_ptr..
I think I traced it to https://github.com/pybind/pybind11/blob/smart_holder/include/pybind11/cast.h#L905 where the automatic and automatic_reference policies are prune before going further with the casting.

@rhaschke
Copy link
Contributor Author

I guess the automatic return value policy is concretized to copy or move in the referenced code snippet and then rejected by the smart_holder_type_caster code. Thus, I think we should allow these policies as well.
@jakobandersen: do you mind preparing a corresponding PR to validate this assumption?

@rwgk
Copy link
Collaborator

rwgk commented Jun 15, 2021

In the meantime, while working on #3023, I found a combination of std::shared_ptr & return_value_policy::copy here:

.def_property_readonly("copy", [](const SharedFromThisRef &s) { return s.value; },
py::return_value_policy::copy)
.def_readonly("holder_ref", &SharedFromThisRef::shared)
.def_property_readonly("holder_copy", [](const SharedFromThisRef &s) { return s.shared; },
py::return_value_policy::copy)

We need to ensure we're compatible with existing behavior, or document the differences if we decide it's better to deviate. — I didn't look enough to be sure what exactly we need to do.

rwgk added a commit to rwgk/pybind11 that referenced this pull request Mar 5, 2025
…major and/or influential contributors to smart_holder branch

* pybind#2904 by @rhaschke was merged on Mar 16, 2021
* pybind#3012 by @rhaschke was merged on May 28, 2021
* pybind#3039 by @jakobandersen was merged on Jun 29, 2021
* pybind#3048 by @Skylion007 was merged on Jun 18, 2021
* pybind#3588 by @virtuald was merged on Jan 3, 2022
* pybind#3633 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3635 by @virtuald was merged on Jan 26, 2022
* pybind#3645 by @wangxf123456 was merged on Jan 25, 2022
* pybind#3796 by @wangxf123456 was merged on Mar 10, 2022
* pybind#3807 by @wangxf123456 was merged on Mar 18, 2022
* pybind#3838 by @wangxf123456 was merged on Apr 15, 2022
* pybind#3929 by @tomba was merged on May 7, 2022
* pybind#4031 by @wangxf123456 was merged on Jun 27, 2022
* pybind#4343 by @wangxf123456 was merged on Nov 18, 2022
* pybind#4381 by @wangxf123456 was merged on Dec 5, 2022
* pybind#4539 by @wangxf123456 was merged on Feb 28, 2023
* pybind#4609 by @wangxf123456 was merged on Apr 6, 2023
* pybind#4775 by @wangxf123456 was merged on Aug 3, 2023
* pybind#4921 by @iwanders was merged on Nov 7, 2023
* pybind#4924 by @iwanders was merged on Nov 6, 2023
* pybind#5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>
rwgk added a commit that referenced this pull request Mar 5, 2025
* Pure `git merge --squash smart_holder` (no manual interventions).

* Remove ubench/ directory.

* Remove include/pybind11/smart_holder.h

* [ci skip] smart_ptrs.rst updates [WIP/unfinished]

* [ci skip] smart_ptrs.rst updates continued; also updating classes.rst, advanced/classes.rst

* Remove README_smart_holder.rst

* Restore original README.rst from master

* [ci skip] Minimal change to README.rst, to leave a hint that this is pybind11v3

* [ci skip] Work in ChatGPT suggestions.

* Change macro name to PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE

* Add a note pointing to the holder reinterpret_cast.

* Incorporate suggestion by @virtuald: #5542 (comment)

* Systematically change most py::class_ to py::classh under docs/

* Remove references to README_smart_holder.rst

This should have been part of commit eb550d0.

* [ci skip] Fix minor oversight (``class_`` -> ``py::class_``) noticed by chance.

* [ci skip] Resolve suggestion by @virtuald

#5542 (comment)

* [ci skip] Apply suggestions by @timohl (thanks!)

* #5542 (comment)
* #5542 (comment)
* #5542 (comment)

* Replace `classh : class_` inhertance with `using`, as suggested by @henryiii

#5542 (comment)

* Revert "Systematically change most py::class_ to py::classh under docs/"

This reverts commit ac9d31e.

* docs: focus on py::smart_holder instead of py::classh

Signed-off-by: Henry Schreiner <[email protected]>

* Restore minor general fixes that got lost when ac9d31e was reverted.

* Remove `- smart_holder` from list of branches in all .github/workflows

* Extend classh note to explain whitespace noise motivation.

* Suggest `py::smart_holder` for "most situations for safety"

* Add back PYBIND11_HAS_INTERNALS_WITH_SMART_HOLDER_SUPPORT

This define was
* introduced with #5286
* removed with #5531

It is has been in use here:
* https://github.com/pybind/pybind11_protobuf/blob/f02a2b7653bc50eb5119d125842a3870db95d251/pybind11_protobuf/native_proto_caster.h#L89-L101

Currently pybind11 unit tests for the two holder caster backwards compatibility traits

* `copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled`
* `move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled`

are missing.

* Add py::trampoline_self_life_support to all trampoline examples under docs/.

Address suggestion by @timohl:

* #5542 (comment)

Add to the "please think twice" note: the overhead for safety is likely in the noise.

Also fix a two-fold inconsistency introduced by revert-commit 1e646c9:

1.

py::trampoline_self_life_support is mentioned in a note, but is missing in the example right before.

2.

The section starting with

    To enable safely passing a ``std::unique_ptr`` to a trampoline object between

is obsolete.

* Fix whitespace accident (indentation) introduced with 1e646c9

Apparently the mis-indentation was introduced when resolving merge conflicts for what became 1e646c9

* WHITESPACE CHANGES ONLY in README.rst (list of people that made significant contributions)

* Add Ethan Steinberg to list of people that made significant contributions (for completeness, unrelated to smart_holder work).

* [ci skip] Add to list of people that made significant contributions: major and/or influential contributors to smart_holder branch

* #2904 by @rhaschke was merged on Mar 16, 2021
* #3012 by @rhaschke was merged on May 28, 2021
* #3039 by @jakobandersen was merged on Jun 29, 2021
* #3048 by @Skylion007 was merged on Jun 18, 2021
* #3588 by @virtuald was merged on Jan 3, 2022
* #3633 by @wangxf123456 was merged on Jan 25, 2022
* #3635 by @virtuald was merged on Jan 26, 2022
* #3645 by @wangxf123456 was merged on Jan 25, 2022
* #3796 by @wangxf123456 was merged on Mar 10, 2022
* #3807 by @wangxf123456 was merged on Mar 18, 2022
* #3838 by @wangxf123456 was merged on Apr 15, 2022
* #3929 by @tomba was merged on May 7, 2022
* #4031 by @wangxf123456 was merged on Jun 27, 2022
* #4343 by @wangxf123456 was merged on Nov 18, 2022
* #4381 by @wangxf123456 was merged on Dec 5, 2022
* #4539 by @wangxf123456 was merged on Feb 28, 2023
* #4609 by @wangxf123456 was merged on Apr 6, 2023
* #4775 by @wangxf123456 was merged on Aug 3, 2023
* #4921 by @iwanders was merged on Nov 7, 2023
* #4924 by @iwanders was merged on Nov 6, 2023
* #5401 by @msimacek was merged on Oct 8, 2024

Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>

---------

Signed-off-by: Henry Schreiner <[email protected]>
Co-authored-by: Henry Schreiner <[email protected]>
Co-authored-by: Aaron Gokaslan <[email protected]>
Co-authored-by: Dustin Spicuzza <[email protected]>
Co-authored-by: Ivor Wanders <[email protected]>
Co-authored-by: Jakob Lykke Andersen <[email protected]>
Co-authored-by: Michael Šimáček <[email protected]>
Co-authored-by: Robert Haschke <[email protected]>
Co-authored-by: Tomi Valkeinen <[email protected]>
Co-authored-by: Xiaofei Wang <[email protected]>
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.

3 participants