@@ -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
4471inline bool PyObjectIsInstanceWithOneOfTpNames(PyObject *obj,
4572 std::initializer_list<const char *> tp_names) {
0 commit comments