-
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
feat: add detail::type_caster_std_function_specializations
#4597
Conversation
07e539e
to
a403cd6
Compare
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.
@lalaland or @Skylion007: Could you please help with an independent review?
Is this change actually necessary? Adding additional specializations like this adds quite a bit to the public API and can be quite clunky to use. Tracking down that functions with a certain return type can be registered / deregistered in this certain way seems like it would be tricky in the long-term IMHO. We already have a lot of issues tracking down various type caster registration things. Can't you get an equivalent result here by making your function take an object as input and have a separate function that casts it so std::function? CC @rwgk |
Thanks for your suggestions! Actually I tried that first. The only problem is that the functions are very similar with the type caster of |
What about a design like this? I understand there will be some redundancy, but it seems that's still a better option than exposing deep internals in a sorta hard to detect way.
|
Thanks very much for the example. I think this works. I am working on some test cases to make sure this supports our needs. |
@wangxf123456 Another thing to think about. You can write a wrapper function that might be better in some situations. Not sure of the exact syntax, but something like the following is probably close
|
@wangxf123456 gentle ping to ask if this PR is still necessary or whether my suggestion was sufficient. Might want to close this PR if this seems to be unnecessary. |
Yes your suggestion is sufficient. Thanks again for sharing! This PR should be unnecessary. |
Note that we already merged this change in |
…81de4e0ae41d861a5c46903968f7b27 The pybind11k `return_value_policy_pack` and `function_record` changes were backed out. The net diffs to PR pybind#4597 are merely: ```diff +#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS ``` ```diff - explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(hf) {} + explicit func_wrapper_base(func_handle &&hf) noexcept : hfunc(std::move(hf)) {} ```
@EthanSteinberg (reviewer in April 2013) @nevedaren (new owner of Python/C++ bindings at Google) Updating this PR to reflect reality: Regarding this comment from May 2023: #4597 (comment)
It unfortunate that this was written, because it was never true. Google has been consistently using this code in production:
Backing out those specializations would have two consequences:
Fundamentally from an engineering quality perspective: any "centralized solution" (specializations in two central places in this case) is better than a solution that requires "sprawling provisions" (e.g. the fixes under 1. above, which could easily number in the hundreds). Contrasting that with these concerns (#4597 (comment)):
I'd argue that is a very minor concern, compared to the many APIs in the
True, the specializations (links above) aren't exactly pretty, but compare that with the alternative of cluttering client code with O(hundreds) of lambda functions, and the greatly increased risk of oversights and related production breakages. I think the cost:benefit ratio is very strongly on the benefit side in this case. I'm leaving Google in less than a month and it's not really my problem anymore. I believe Google doesn't have a viable alternative to carrying the current adaption of this PR (under #5289) indefinitely. It is plausible that only pybind/pybind11_abseil users will need the specializations, but then again,
Having the option for the specializations merged upstream will help us all collaborating efficiently. (I already spent hours worth of my time just juggling this patch.) |
I'll try to modernize this PR. |
type_caster_std_function_specializations
feature.
@rwgk it sounds like I was incorrect, and the benefit of this PR is worth the complexity cost, and it should probably be added to pybind11 Thanks for providing the additional context and explanation |
Thanks @EthanSteinberg! I'll go ahead with merging this PR. In addition to the other things mentioned, it's really helping me making the job-change related hand-over as smooth as possible. |
* Allow specializations based on callback function return values. * clang-tidy auto fix * Add a test case for function specialization. * Add test for callback function that raises Python exception. * Fix test failures. * style: pre-commit fixes * Add `#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS` --------- Co-authored-by: Ralf W. Grosse-Kunstleve <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
type_caster_std_function_specializations
feature.detail::type_caster_std_function_specializations
* Allow specializations based on callback function return values. * clang-tidy auto fix * Add a test case for function specialization. * Add test for callback function that raises Python exception. * Fix test failures. * style: pre-commit fixes * Add `#define PYBIND11_HAS_TYPE_CASTER_STD_FUNCTION_SPECIALIZATIONS` --------- Co-authored-by: Ralf W. Grosse-Kunstleve <[email protected]> Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Description
For callback functions that throw Python exceptions, we might want to handle it inside the
func_wrapper
specializations, instead of throwing the uncaughtpybind11::error_already_set
exception.Note that the production code change is a completely straightforward local refactoring, simply moving two types from class scope to namespace scope. The increase in code complexity is very minor, the compile time increase is probably in the measurement noise, and the runtime overhead is expected to be zero.
The exact case we want to support is callback functions with
absl::Status
andabsl::StatusOr
return values. If the status it not ok, an exception will be thrown: https://github.com/pybind/pybind11_abseil/blob/429ae15db6c8d6ccac21bf6e1a84e92ab1d2c1a4/pybind11_abseil/status_caster.h#L110. But for callback functions, in some situations we don't want to propagate any exception. Instead, we want to convert the exception to anabsl::Status
Python object.Suggested changelog entry: