@@ -76,8 +76,8 @@ Conservative or Progressive mode?
7676=================================
7777
7878It 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
8181mode may be more practical, at least initially, although it comes with the
8282disadvantage of having to use the ``PYBIND11_SMART_HOLDER_TYPE_CASTERS `` macro.
8383
@@ -120,40 +120,40 @@ could probably be avoided with a little bit of template metaprogramming).
120120
121121To the 3rd bullet point, the macro also needs to appear in other translation
122122units 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 ,
124124at a larger scale it is best to work with a pair of `.h ` and `.cpp ` files
125125for the bindings code, with the macros in the `.h ` files.
126126
127127
128128Progressive mode
129129----------------
130130
131- To work in progressive mode:
131+ To work in Progressive mode:
132132
133133- Add ``-DPYBIND11_USE_SMART_HOLDER_AS_DEFAULT `` to the compilation commands.
134134
135135- 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.
138137
139138- Only if custom smart-pointers are used: the
140139 `PYBIND11_TYPE_CASTER_BASE_HOLDER ` macro is needed [`example
141140 <https://github.com/pybind/pybind11/blob/2f624af1ac8571d603df2d70cb54fc7e2e3a356a/tests/test_multiple_inheritance.cpp#L72> `_].
142141
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
144143
145144- the macro inconvenience is shifted from ``py::smart_holder `` to custom
146145 smart-pointers (but probably much more rarely needed).
147146
148147- 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).
150150
151151
152- Transition from conservative to progressive mode
152+ Transition from Conservative to Progressive mode
153153------------------------------------------------
154154
155155This 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
157157fashion. In large-scale situations it seems more likely that an incremental
158158approach is needed, which could mean incrementally converting ``py::class_ ``
159159to ``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
175175tests/test_classh_mock.cpp for an example.
176176
177177
178- Classic / conservative / progressive cross-module compatibility
178+ Classic / Conservative / Progressive cross-module compatibility
179179---------------------------------------------------------------
180180
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:
182183
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.
186185
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:
189193
190194.. list-table :: Compatibility matrix
191195 :widths: auto
@@ -204,11 +208,11 @@ matrix for ``py::class_``-wrapped types:
204208 * -
205209 - **Classic **
206210 - full
207- - one-way
211+ - one-and-a-half- way
208212 - isolated
209213 * - **Module 1 **
210214 - **Conservative **
211- - one-way
215+ - one-and-a-half- way
212216 - full
213217 - isolated
214218 * -
@@ -217,6 +221,36 @@ matrix for ``py::class_``-wrapped types:
217221 - isolated
218222 - full
219223
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+
220254
221255Trampolines and std::unique_ptr
222256-------------------------------
@@ -256,8 +290,8 @@ GitHub testing of PRs against the smart_holder branch
256290-----------------------------------------------------
257291
258292PRs 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
261295testing. Currently this is handled simply by creating a secondary PR with a
262296one-line change in ``include/pybind11/detail/smart_holder_sfinae_hooks_only.h ``
263297(as in e.g. `PR #2879 <https://github.com/pybind/pybind11/pull/2879 >`_). It
@@ -273,7 +307,7 @@ primary PR as needed:
273307 git checkout sh_secondary_pr
274308 git rebase -X theirs sh_primary_pr
275309 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.
277311
278312 The second time through this will only take a minute or two.
279313
0 commit comments