@@ -76,8 +76,8 @@ Conservative or Progressive mode?
76
76
=================================
77
77
78
78
It depends. To a first approximation, for a stand-alone, new project, the
79
- progressive mode will be easiest to use. For larger projects or projects
80
- that integrate with third-party pybind11-based projects, the conservative
79
+ Progressive mode will be easiest to use. For larger projects or projects
80
+ that integrate with third-party pybind11-based projects, the Conservative
81
81
mode may be more practical, at least initially, although it comes with the
82
82
disadvantage of having to use the ``PYBIND11_SMART_HOLDER_TYPE_CASTERS `` macro.
83
83
@@ -120,40 +120,40 @@ could probably be avoided with a little bit of template metaprogramming).
120
120
121
121
To the 3rd bullet point, the macro also needs to appear in other translation
122
122
units with pybind11 bindings that involve Python⇄C++ conversions for
123
- `Foo `. This is the biggest inconvenience of the conservative mode. Practially ,
123
+ `Foo `. This is the biggest inconvenience of the Conservative mode. Practically ,
124
124
at a larger scale it is best to work with a pair of `.h ` and `.cpp ` files
125
125
for the bindings code, with the macros in the `.h ` files.
126
126
127
127
128
128
Progressive mode
129
129
----------------
130
130
131
- To work in progressive mode:
131
+ To work in Progressive mode:
132
132
133
133
- Add ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT `` to the compilation commands.
134
134
135
135
- Remove any ``std::shared_ptr<...> `` holders from existing ``py::class_ ``
136
- instantiations (#HelpAppreciated this could probably be avoided with a little
137
- bit of template metaprogramming).
136
+ instantiations.
138
137
139
138
- Only if custom smart-pointers are used: the
140
139
`PYBIND11_TYPE_CASTER_BASE_HOLDER ` macro is needed [`example
141
140
<https://github.com/pybind/pybind11/blob/2f624af1ac8571d603df2d70cb54fc7e2e3a356a/tests/test_multiple_inheritance.cpp#L72> `_].
142
141
143
- Overall this is probably easier to work with than the conservative mode, but
142
+ Overall this is probably easier to work with than the Conservative mode, but
144
143
145
144
- the macro inconvenience is shifted from ``py::smart_holder `` to custom
146
145
smart-pointers (but probably much more rarely needed).
147
146
148
147
- it will not interoperate with other extensions built against master or
149
- stable, or extensions built in conservative mode.
148
+ stable, or extensions built in Conservative mode (see the cross-module
149
+ compatibility section below).
150
150
151
151
152
- Transition from conservative to progressive mode
152
+ Transition from Conservative to Progressive mode
153
153
------------------------------------------------
154
154
155
155
This still has to be tried out more in practice, but in small-scale situations
156
- it may be feasible to switch directly to progressive mode in a break-fix
156
+ it may be feasible to switch directly to Progressive mode in a break-fix
157
157
fashion. In large-scale situations it seems more likely that an incremental
158
158
approach is needed, which could mean incrementally converting ``py::class_ ``
159
159
to ``py::classh `` including addition of the macros, then flip the switch,
@@ -175,17 +175,21 @@ still being able to build the same code with classic pybind11. Please see
175
175
tests/test_classh_mock.cpp for an example.
176
176
177
177
178
- Classic / conservative / progressive cross-module compatibility
178
+ Classic / Conservative / Progressive cross-module compatibility
179
179
---------------------------------------------------------------
180
180
181
- Currently there are essentially three modes for building a pybind11 extension module:
181
+ Currently there are essentially three modes for building a pybind11 extension
182
+ module:
182
183
183
- * Classic: pybind11 stable (e.g. v2.6.2) or current master
184
- * Conservative: pybind11 smart_holder
185
- * Progressive: pybind11 smart_holder with ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT ``
184
+ - Classic: pybind11 stable (e.g. v2.6.2) or current master branch.
186
185
187
- In environments that mix modules built with different modes, this is the compatibility
188
- matrix for ``py::class_ ``-wrapped types:
186
+ - Conservative: pybind11 smart_holder branch.
187
+
188
+ - Progressive: pybind11 smart_holder branch with
189
+ ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT ``.
190
+
191
+ In environments that mix extension modules built with different modes,
192
+ this is the compatibility matrix for ``py::class_ ``-wrapped types:
189
193
190
194
.. list-table :: Compatibility matrix
191
195
:widths: auto
@@ -204,11 +208,11 @@ matrix for ``py::class_``-wrapped types:
204
208
* -
205
209
- **Classic **
206
210
- full
207
- - one-way
211
+ - one-and-a-half- way
208
212
- isolated
209
213
* - **Module 1 **
210
214
- **Conservative **
211
- - one-way
215
+ - one-and-a-half- way
212
216
- full
213
217
- isolated
214
218
* -
@@ -217,6 +221,36 @@ matrix for ``py::class_``-wrapped types:
217
221
- isolated
218
222
- full
219
223
224
+ Mixing Classic+Progressive or Conservative+Progressive is very easy to
225
+ understand: the extension modules are essentially completely isolated from
226
+ each other. This is in fact just the same as using pybind11 versions with
227
+ differing `"internals version"
228
+ <https://github.com/pybind/pybind11/blob/114be7f4ade0ad798cd4c7f5d65ebe4ba8bd892d/include/pybind11/detail/internals.h#L95> `_
229
+ in the past. While this is easy to understand, there is also no incremental
230
+ transition path between Classic and Progressive.
231
+
232
+ The Conservative mode enables incremental transitions, but at the cost of
233
+ more complexity. Types wrapped in a Classic module are fully compatible with
234
+ a Conservative module. However, a type wrapped in a Conservative module is
235
+ compatible with a Classic module only if ``py::smart_holder `` is **not ** used
236
+ (for that type). A type wrapped with ``py::smart_holder `` is incompatible with
237
+ a Classic module. This is an important pitfall to keep in mind: attempts to use
238
+ ``py::smart_holder ``-wrapped types in a Classic module will lead to undefined
239
+ runtime behavior, such as a SEGFAULT. This is a more general flavor of the
240
+ long-standing issue `#1138 <https://github.com/pybind/pybind11/issues/1138 >`_,
241
+ often referred to as "holder mismatch". It is important to note that the
242
+ pybind11 smart_holder branch solves the smart-pointer interoperability issue,
243
+ but not the more general holder mismatch issue. — Unfortunately the existing
244
+ pybind11 internals do not track holder runtime type information, therefore
245
+ the holder mismatch issue cannot be solved in a fashion that would allow
246
+ an incremental transition, which is the whole point of the Conservative
247
+ mode. Please proceed with caution.
248
+
249
+ Another pitfall worth pointing out specifically, although it follows
250
+ from the previous: mixing base and derived classes between Classic and
251
+ Conservative modules means that neither the base nor the derived class can
252
+ use ``py::smart_holder ``.
253
+
220
254
221
255
Trampolines and std::unique_ptr
222
256
-------------------------------
@@ -256,8 +290,8 @@ GitHub testing of PRs against the smart_holder branch
256
290
-----------------------------------------------------
257
291
258
292
PRs against the smart_holder branch need to be tested in both
259
- modes (conservative, progressive ), with the only difference that
260
- ``PYBIND11_USE_SMART_HOLDER_AS_DEFAULT `` is defined for progressive mode
293
+ modes (Conservative, Progressive ), with the only difference that
294
+ ``PYBIND11_USE_SMART_HOLDER_AS_DEFAULT `` is defined for Progressive mode
261
295
testing. Currently this is handled simply by creating a secondary PR with a
262
296
one-line change in ``include/pybind11/detail/smart_holder_sfinae_hooks_only.h ``
263
297
(as in e.g. `PR #2879 <https://github.com/pybind/pybind11/pull/2879 >`_). It
@@ -273,7 +307,7 @@ primary PR as needed:
273
307
git checkout sh_secondary_pr
274
308
git rebase -X theirs sh_primary_pr
275
309
git diff # To verify that the one-line change in smart_holder_sfinae_hooks_only.h is the only diff.
276
- git push --force-with-lease # This will trigger the GitHub Actions for the progressive mode.
310
+ git push --force-with-lease # This will trigger the GitHub Actions for the Progressive mode.
277
311
278
312
The second time through this will only take a minute or two.
279
313
0 commit comments