Factor out readable function signatures to avoid duplication#5857
Factor out readable function signatures to avoid duplication#5857rwgk merged 10 commits intopybind:masterfrom
Conversation
This seems to reduce size costs of adding enum_-specific implementations of dunder methods, but also should provide a nice to have size optimization for programs that use pybind11 in general.
|
Hmm, I could've sworn I saw Apple Clang 15 raise -Wdeprecated-redundant-constexpr-static-def, but here it is, claiming not to know about that warning: https://github.com/pybind/pybind11/actions/runs/18418181095/job/52486700109?pr=5857#step:11:123 Also, here is clang 16 calling it a plain old -Wdeprecated: https://github.com/pybind/pybind11/actions/runs/18418181095/job/52486699145?pr=5857#step:6:70 |
rwgk
left a comment
There was a problem hiding this comment.
Looks fine to me. My suggestions are purely about naming and comments.
include/pybind11/pybind11.h
Outdated
| #define PYBIND11_READABLE_SIGNATURE_EXPR \ | ||
| detail::const_name("(") + cast_in::arg_names + detail::const_name(") -> ") + cast_out::name | ||
|
|
||
| // We centralize readable function signatures in a specific template |
There was a problem hiding this comment.
The word "centralize" here was throwing me off when I first looked at this PR. It led me to think you're making the source code more DRY, but apparently that's not what this PR does?
How about writing
// We factor out readable function signatures ...
?
// so that we don't duplicate them across different ...
Is it really "we"? It'd be the compiler? But a smart-enough compiler could do that regardless, maybe that's why some .sos are still the same size?
How about
// so that we can be sure compilers don't duplicate them across different ...
There was a problem hiding this comment.
// We factor out readable function signatures ...
Yep, I think that is much more straightforward and standard wording. Thank you. Also revising the PR title.
a smart-enough compiler could do that regardless
While this is technically true (c.f. the LLVM MachineOutliner), I think automatic outlining of large portions of templated functions is generally beyond reasonable expectations for C++ compilers, and so we shouldn't blame them for duplication happening. Having to extract portions of templates to non-generic code to avoid bloat is usual practice (and pybind11 itself does that with initialize_generic in this same codepath!); the difference here is we are extracting to less-generic code (fewer template arguments) rather than non-generic code.
How about a neutral framing like
// so that they don't get duplicated across different...
include/pybind11/pybind11.h
Outdated
| }; | ||
| #undef PYBIND11_READABLE_SIGNATURE_EXPR | ||
|
|
||
| // Prior to C++17, we don't have inline variables, so we have to provide an out-of-line definition |
There was a problem hiding this comment.
Wow, that's a pretty big block of pure ugliness, even by the usual C++ standards ...
Could you please add a comment to prominently suggest that this block is removed when C++11 and C++ 14 support is dropped?
include/pybind11/pybind11.h
Outdated
| # define PYBIND11_COMPAT_STRDUP strdup | ||
| #endif | ||
|
|
||
| #define PYBIND11_READABLE_SIGNATURE_EXPR \ |
There was a problem hiding this comment.
PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR
for consistency. — Since this is used only in a couple places, I think consistency is more valuable than trimming the length of the name.
include/pybind11/pybind11.h
Outdated
| template <typename cast_in, typename cast_out> | ||
| class ReadableFunctionSignature { | ||
| public: | ||
| using readable_signature_type = decltype(PYBIND11_READABLE_SIGNATURE_EXPR); |
There was a problem hiding this comment.
Within this scope shorter names would make this code more readable, e.g. simply sig_type here, and static constexpr sig_type sig(), kSig or similar below.
There was a problem hiding this comment.
Good point. ReadableFunctionSignature::kReadableSignature is redundant.
|
|
||
| public: | ||
| static constexpr readable_signature_type kReadableSignature = readable_signature(); | ||
| #if !defined(_MSC_VER) |
There was a problem hiding this comment.
Could you please add a comment to explain (or at least hint) why this works only with compilers other than MSVC?
| }; | ||
| #undef PYBIND11_READABLE_FUNCTION_SIGNATURE_EXPR | ||
|
|
||
| // Prior to C++17, we don't have inline variables, so we have to |
There was a problem hiding this comment.
C++17 also made static constexpr variables inline by default. Could you suppress the definitions in C++17 mode rather than adding the warnings? I think that might make this clearer
There was a problem hiding this comment.
good idea. I will try that now.
Description
This should provide a nice to have size optimization for programs that use pybind11 in general. I wrote it because it seems to reduce size costs of adding enum_-specific implementations of dunder methods, but since it seems generally useful, I thought it might be a good idea to send as a separate PR.
Concretely, for the pybind11_tests.cpython-313-darwin.so file built as part of pybind11's tests, I see the following size delta (output is
sdiffofsize -m):Full disclosure: Not all of the other .sos improved (though none regressed). For this to show a benefit, users' pybind11 extensions would have to define multiple pybind11 functions or methods with the same signature.
Suggested changelog entry: