-
Notifications
You must be signed in to change notification settings - Fork 2.1k
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
squash-merge smart_holder branch into master #5542
squash-merge smart_holder branch into master #5542
Conversation
…, advanced/classes.rst
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Only reviewed documentation.
I note that the documentation doesn't mention PYBIND11_USE_SMART_HOLDER_AS_DEFAULT
at all. In my usage of pybind11, I enable that macro because (a) I'm lazy and (b) I assumed that because smart holder is awesome that eventually when it got merged it would become the default and then we could get rid of the macro.
I don't understand the backwards compatibility argument for not making smart holder the default, but if there really are known backwards compatibility issues and it's not going to be the default I think I lean towards getting rid of the macro? When reading pybind11 code it would be good to know "this is definitely using smart holder" and "this is definitely not" without having to know which compile flags are set.
Edit: lol clearly I didn't read the PR description carefully enough
docs/classes.rst
Outdated
|
||
.. note:: | ||
|
||
Starting with pybind11v3, it is recommended to use `py::classh` in most |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe it's another PR, but since it's the recommended default, we probably should change all of the documentation to use it, since users often just copy/paste from the documentation without thinking about it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was on the fence, thanks for the feedback! I'll change it around.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done in commit ac9d31e.
(I made a fast pass, followed by a careful slow pass reviewing the generated html.)
@virtuald As someone who's used the smart_holder branch for a long time, what's you opinion about this question?
It only makes a difference to people who have been using the smart_holder branch before (probably a relative small number?). When they switch to pbyind11v3, they'll be forced to adjust their code (remove pybind11/smart_holder.h includes). Is that a hardship, or just a minor inconvenience? |
.. seealso:: | ||
|
||
The file :file:`tests/test_smart_ptr.cpp` contains a complete example | ||
that demonstrates how to work with custom reference-counting holder types | ||
in more detail. | ||
|
||
|
||
Be careful not to accidentally undermine automatic lifetime management |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe I missed it, but is this a new section that has nothing to do with smart holder? Maybe move it to a separate PR.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, it's definitely odd here, but it's based on this existing part:
pybind11/docs/advanced/smart_ptrs.rst
Lines 50 to 113 in d8565ac
One potential stumbling block when using holder types is that they need to be | |
applied consistently. Can you guess what's broken about the following binding | |
code? | |
.. code-block:: cpp | |
class Child { }; | |
class Parent { | |
public: | |
Parent() : child(std::make_shared<Child>()) { } | |
Child *get_child() { return child.get(); } /* Hint: ** DON'T DO THIS ** */ | |
private: | |
std::shared_ptr<Child> child; | |
}; | |
PYBIND11_MODULE(example, m) { | |
py::class_<Child, std::shared_ptr<Child>>(m, "Child"); | |
py::class_<Parent, std::shared_ptr<Parent>>(m, "Parent") | |
.def(py::init<>()) | |
.def("get_child", &Parent::get_child); | |
} | |
The following Python code will cause undefined behavior (and likely a | |
segmentation fault). | |
.. code-block:: python | |
from example import Parent | |
print(Parent().get_child()) | |
The problem is that ``Parent::get_child()`` returns a pointer to an instance of | |
``Child``, but the fact that this instance is already managed by | |
``std::shared_ptr<...>`` is lost when passing raw pointers. In this case, | |
pybind11 will create a second independent ``std::shared_ptr<...>`` that also | |
claims ownership of the pointer. In the end, the object will be freed **twice** | |
since these shared pointers have no way of knowing about each other. | |
There are two ways to resolve this issue: | |
1. For types that are managed by a smart pointer class, never use raw pointers | |
in function arguments or return values. In other words: always consistently | |
wrap pointers into their designated holder types (such as | |
``std::shared_ptr<...>``). In this case, the signature of ``get_child()`` | |
should be modified as follows: | |
.. code-block:: cpp | |
std::shared_ptr<Child> get_child() { return child; } | |
2. Adjust the definition of ``Child`` by specifying | |
``std::enable_shared_from_this<T>`` (see cppreference_ for details) as a | |
base class. This adds a small bit of information to ``Child`` that allows | |
pybind11 to realize that there is already an existing | |
``std::shared_ptr<...>`` and communicate with it. In this case, the | |
declaration of ``Child`` should look as follows: | |
.. _cppreference: http://en.cppreference.com/w/cpp/memory/enable_shared_from_this | |
.. code-block:: cpp | |
class Child : public std::enable_shared_from_this<Child> { }; |
I think it'll be best to move it only after this PR is merged, to not make this PR even more difficult to review.
No promises were really made about smart_holder and if one is using (what is effectively) a fork of a project then you just accept whatever comes with it, so I think whatever makes sense would be good. Since everything in that file is marked as deprecated, it seems good to get rid of it. Looking at my own usage, I used |
Thanks! I'm glad to get rid of it completely. I'll remove my note from the PR description.
I want to nudge people towards not ever using that macro in production situations, with this in mind:
One idea is to rename the macro, .e.g.: So in your case the old name would become a no-op, some tests would break, which you'd then fix by changing your I'm trying to think ahead, please chime in if I'm going off the tracks: You wouldn't be able to go back to an older pybind11 version easily. But then again, if your code requires the smart_holder feature, that wouldn't work anyway. So all good? But what will people do if I'm overlooking something and they have a reason to use They could go through their code to change |
…T_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
This should have been part of commit eb550d0.
@timohl, could you help with a second set of eyes reviewing the documentation changes and the PR description? |
@henryiii, can you think of anything that I might be overlooking? |
@lanctot, could you help reviewing the documentation changes and the PR description? Will this work for https://github.com/google-deepmind/open_spiel? |
@isuruf for awareness mainly. — But please let me know if you believe this PR will cause issues for Conda. (I don't think so; I believe any adjustments that may be needed on the Conda side (for migrating to pybind11 v3.0.0) will be for changes that exist on pybind11 master already.) |
Sure. I can check tomorrow. |
c08b428
to
d3f9f93
Compare
I added 4 commits. The first two restore or add mechanical fixes: This one clarifies why the number of characters in
This one strengthens the case for
I feel the pendulum has swung a little too far in the opposite direction. Previously the emphasis on I'm OK, though, to merge this PR as it is now. |
FWIW, ChatGPT is giving passing marks to the docs/ changes: https://chatgpt.com/share/67c33999-7d70-8008-a58d-522886466b1c The production code changes (under include/) relative to the smart_holder branch are minimal. |
This define was * introduced with pybind#5286 * removed with pybind#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.
I added a commit to add back the Copying the commit message here for easy reference: Add back This
It is has been in use here: Currently pybind11 unit tests for the two holder caster backwards compatibility traits
are missing. I'll add tests after this PR is merged. That code only compiles with a Thanks @itamaro for testing this PR and pointing out that duckdb code! |
What is the motivation of a squash merge? Why nuke all the history of smart holder? |
The history will stay around indefinitely: I will rename the branch to archive/smart_holder, but I will not delete it. This explains how the history will stay around (also touches on |
… docs/. Address suggestion by @timohl: * pybind#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.
Apparently the mis-indentation was introduced when resolving merge conflicts for what became 1e646c9
Thanks @henryiii! I'll merge this asap, but I want to do this first: ChatGPT prompt:
Response: https://chatgpt.com/share/67c77bef-c554-8008-b23d-3ebab2b1572b |
…ficant contributions)
…ions (for completeness, unrelated to smart_holder work).
…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 <aaronGokaslan@gmail.com> Co-authored-by: Dustin Spicuzza <dustin@virtualroadside.com> Co-authored-by: Ivor Wanders <iwanders@users.noreply.github.com> Co-authored-by: Jakob Lykke Andersen <Jakob@caput.dk> Co-authored-by: Michael Šimáček <michael.simacek@oracle.com> Co-authored-by: Robert Haschke <rhaschke@users.noreply.github.com> Co-authored-by: Tomi Valkeinen <tomi.valkeinen@iki.fi> Co-authored-by: Xiaofei Wang <6218006+wangxf123456@users.noreply.github.com>
Not rerunning GitHub Actions before merging: The last three commits (9bb8d06, b9bf98a, 8e432e9) only update the top-level README.rst I added For visibility: |
I want to say thank you very much to:
My main goal was to reunify the entire pybind11 ecosystem, and I hope this work brings lasting benefits to everyone. |
Huge thanks to everyone involved here, everyone in the pybind11 team and rwgk especially! This branch and the pybind11 project are providing huge value to us, making many things possible which would otherwise be far out of reach for us! Huge thanks!!!! |
Description
EDIT: The smart_holder branch was archived here after this PR was merged.
Notes:
For benchmarking results, see PR [smart_holder] smart_holder / master benchmarking 2025-02-16 #5529.
The only one existing (on master) test that is changed slightly is test_class.cpp/py. This is only to accommodate testing with
PYBIND11_RUN_TESTING_WITH_SMART_HOLDER_AS_DEFAULT_BUT_NEVER_USE_IN_PRODUCTION_PLEASE
(this exists primarily to ensure thatpy::smart_holder
is fully compatible with all existing functionality).All code was formally reviewed at least once. Much of the code was formally reviewed multiple times (as it was moved around between branches).
The only changes not reviewed already were merged (into smart_holder) under PR [smart_holder] Remove obsolete
detail::type_info::default_holder
member. #5541. All other code has been in production use at Google since September 2024. The smart_holder branch has been in production use at Google since February 2021. I.e. this code is extremely thoroughly tested. Additionally, testing via PyCLIF-pybind11 provided thousands of diverse use cases that needed to satisfy many million unit tests (the PyCLIF-pybind11 success was about 99.999%).The only significant updates under
docs/
are indocs/advanced/smart_ptrs.rst
anddocs/advanced/classes.rst
. The rest of thedocs/
updates are mostly mechanical, to replacepy::class_
withpy::classh
(based on this rationale).For easy reference, other recent PRs enabling this one:
PYBIND11_INTERNALS_VERSION
s4
and5
#5530The following is for this PR at commit a4cfd38:
git diff
counts under include/:git diff master include/ | grep '^-' | grep -v '^---' | wc -l
)git diff master include/ | grep '^+' | grep -v '^+++' | wc -l
)I.e., the existing production code is barely touched.
Similarly for tests/:
For more detail, results produced by
cloc --diff
for include/ between the master branch and this PR:I.e., this PR increases the production code size by 7.8%.
The squash-commit cd1c9d4 includes these smart_holder PRs not authored by @rwgk, sorted chronologically:
return_as_bytes
#3838 by @wangxf123456 was merged on Apr 15, 2022unique_ptr<Derived>
asunique_ptr<Base>
. #4031 by @wangxf123456 was merged on Jun 27, 2022_clif_automatic
#4343 by @wangxf123456 was merged on Nov 18, 2022try_as_void_ptr_capsule
as a free function #4539 by @wangxf123456 was merged on Feb 28, 2023unique_ptr
acceptautomatic_reference
#4775 by @wangxf123456 was merged on Aug 3, 2023Suggested changelog entry:
To be covered in the upgrade guide:
copyable_holder_caster_shared_ptr_with_smart_holder_support_enabled
move_only_holder_caster_unique_ptr_with_smart_holder_support_enabled