You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
C API: Implement singletons as functions calls in the stable ABI 3.13 #115754
I propose to export important constants as symbols in the stable ABI and the limited C API, but still implement them as macros in the non-limited C API.
I also tried a different approach, use static const:
diff --git a/Include/boolobject.h b/Include/boolobject.h
index 19aef5b1b8..a841bf1587 100644
--- a/Include/boolobject.h+++ b/Include/boolobject.h@@ -18,8 +18,8 @@ PyAPI_DATA(PyLongObject) _Py_FalseStruct;
PyAPI_DATA(PyLongObject) _Py_TrueStruct;
/* Use these macros */
-#define Py_False _PyObject_CAST(&_Py_FalseStruct)-#define Py_True _PyObject_CAST(&_Py_TrueStruct)+static PyObject * const Py_False = _PyObject_CAST(&_Py_FalseStruct);+static PyObject * const Py_True = _PyObject_CAST(&_Py_TrueStruct);
// Test if an object is the True singleton, the same as "x is True" in Python.
PyAPI_FUNC(int) Py_IsTrue(PyObject *x);
But it changes the constant type (make them constant in the limited C API), and it doesn't work with dlopen/dlsym.
Can we export them as functions rather than symbols? Symbols are the reason we've struggled so hard to get the isolation we want, because we have to invent tricky solutions that wouldn't have been necessary had they been functions.
And if functions, why not Py_GetConstant(int) and an enum to select which one is wanted? That's way more easily manageable from our POV (we'd want to document that the constant comes with an incremented refcount and is only valid in the active interpreter).
I'm not sure how to categorize "important" vs "non-important" constants.
Well no, they could all use the same API if they want, it'd just be the function one ;-)
And the stable ABI can be Py_GetConstant(PY_NONE) while the limited API includes #define Py_None Py_GetConstant(PY_NONE). It adds some overhead, obviously, but if we'd done it this way from the start then we wouldn't have the overhead on all the INCREF/DECREF calls instead (because we wouldn't have needed to immortalise static types and constants).
Maybe we've run out of reasons that a function would be better than a data reference? I don't see any reason to assume that, and so I think having a function would be a safer ABI.
Symbols are the reason we've struggled so hard to get the isolation we want
Which isolation are you talking about?
I don't get which problem you're trying to solve by using a function.
#define Py_None Py_GetConstant(PY_NONE)
Ah right, you would have the same API this way.
But why would these specific constants need an indirection to pass through a function call whereas all other variables (PyAPI_DATA), such as Py_Version, are directly accessible?
Activity
pythongh-115754: Export Py_None, Py_False, Py_True as symbols
pythongh-115754: Export Py_None, Py_False, Py_True as symbols
pythongh-115754: Export Py_None, Py_False, Py_True as symbols
vstinner commentedon Feb 21, 2024
cc @encukou @davidhewitt @da-woods who might be interested by the topic.
vstinner commentedon Feb 21, 2024
I also tried a different approach, use
static const:But it changes the constant type (make them constant in the limited C API), and it doesn't work with dlopen/dlsym.
cc @pitrou
vstinner commentedon Feb 21, 2024
I'm not sure how to categorize "important" vs "non-important" constants.
Maybe only "pointers" to variables are interesting?
Example of constants:
In vim, I looked for
:grep '\# *define [A-Za-z0-9_]\+ \+[^ \\]' Include/*.h.pythongh-115754: Export Py_None, Py_False, Py_True as symbols
zooba commentedon Feb 21, 2024
Can we export them as functions rather than symbols? Symbols are the reason we've struggled so hard to get the isolation we want, because we have to invent tricky solutions that wouldn't have been necessary had they been functions.
zooba commentedon Feb 21, 2024
And if functions, why not
Py_GetConstant(int)and an enum to select which one is wanted? That's way more easily manageable from our POV (we'd want to document that the constant comes with an incremented refcount and is only valid in the active interpreter).My vote is for "important ones are
PyObject *"pythongh-115754: Export Py_None, Py_False, Py_True as symbols
vstinner commentedon Feb 21, 2024
Sure, it's possible. But it would be slower and require C extensions to have a different API than the non-limited C API, no?
I have a working implementation where
Py_Noneand other constants are exported as symbols ("variables") and implemented as macros: best of both world.zooba commentedon Feb 21, 2024
Well no, they could all use the same API if they want, it'd just be the function one ;-)
And the stable ABI can be
Py_GetConstant(PY_NONE)while the limited API includes#define Py_None Py_GetConstant(PY_NONE). It adds some overhead, obviously, but if we'd done it this way from the start then we wouldn't have the overhead on all the INCREF/DECREF calls instead (because we wouldn't have needed to immortalise static types and constants).Maybe we've run out of reasons that a function would be better than a data reference? I don't see any reason to assume that, and so I think having a function would be a safer ABI.
vstinner commentedon Feb 21, 2024
Which isolation are you talking about?
I don't get which problem you're trying to solve by using a function.
Ah right, you would have the same API this way.
But why would these specific constants need an indirection to pass through a function call whereas all other variables (PyAPI_DATA), such as Py_Version, are directly accessible?
30 remaining items
Squashed commit of the following:
Squashed commit of the following:
pythongh-115754: Add Py_GetConstant() function (python#116883)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)
gh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES) (#125195)
gh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR) (#125194)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_BYTES)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR)
gh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR) (#125583)
pythongh-115754: Use Py_GetConstant(Py_CONSTANT_EMPTY_STR) (python#12…