Skip to content

Commit 1fa338e

Browse files
committed
Add a long C++ comment explaining what led to the PyObjectTypeIsConvertibleTo*() implementations.
1 parent da29bf5 commit 1fa338e

File tree

1 file changed

+28
-1
lines changed

1 file changed

+28
-1
lines changed

include/pybind11/stl.h

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,34 @@ PYBIND11_NAMESPACE_BEGIN(detail)
3939
//
4040
// Begin: Equivalent of
4141
// https://github.com/google/clif/blob/337b2a106c0552ad85d40cfc3797465756840ea0/clif/python/runtime.cc#L388-L424
42-
//
42+
/*
43+
The three `PyObjectTypeIsConvertibleTo*()` functions below are
44+
the result of converging the behaviors of pybind11 and PyCLIF
45+
(http://github.com/google/clif).
46+
47+
Originally PyCLIF was extremely far on the permissive side of the spectrum,
48+
while pybind11 was very far on the strict side. Originally PyCLIF accepted any
49+
Python iterable as input for a C++ `vector`/`set`/`map` argument, as long as
50+
the elements were convertible. The obvious (in hindsight) problem was that
51+
any empty Python iterable could be passed to any of these C++ types, e.g. `{}`
52+
was accpeted for C++ `vector`/`set` arguments, or `[]` for C++ `map` arguments.
53+
54+
The functions below strike a practical permissive-vs-strict compromise,
55+
informed by tens of thousands of use cases in the wild. A main objective is
56+
to prevent accidents and improve readability:
57+
58+
- Python literals must match the C++ types.
59+
60+
- For C++ `set`: The potentially reducing conversion from a Python sequence
61+
(e.g. Python `list` or `tuple`) to a C++ `set` must be explicit, by going
62+
through a Python `set`.
63+
64+
- However, a Python `set` can still be passed to a C++ `vector`. The rationale
65+
is that this conversion is not reducing. Implicit conversions of this kind
66+
are also fairly commonly used, therefore enforcing explicit conversions
67+
would have an unfavorable cost : benefit ratio; more sloppily speaking,
68+
such an enforcement would be more annyoing than helpful.
69+
*/
4370

4471
inline bool PyObjectIsInstanceWithOneOfTpNames(PyObject *obj,
4572
std::initializer_list<const char *> tp_names) {

0 commit comments

Comments
 (0)