Hi,
In my previous "Open questions about borrowed references" thread, I asked if it's an issue or not that Py_TYPE() returns a borrowed reference.
It seems like most people say that it's not an issue. If you want to discuss if Py_TYPE() is an issue, please contribute to the other thread. Here I only want to share my results. Honestly, I'm still not 100% convinced that Py_TYPE() is an issue :-)
I experimented anyway a C API without Py_TYPE(). I chose to add 3 functions/features:
Py_GetType()
: similar toPy_TYPE()
but returns a strong referencePy_TYPE_IS(ob, type)
: equivalent toPy_TYPE(ob) == type
%T
format forPyUnicode_FromFormat()
Most of the usage of Py_TYPE() are the following 5 patterns. For the last one, I'm not sure that the "N" format of Py_BuildValue() should stay since it's also based on borrowed reference. Replacing Py_TYPE() requires a lot of changes, and I made many copy/paste mistakes. If we chose to remove Py_TYPE(), we really need a tool to automate refactoring. Otherwise, the risk of introducing a regression is just too high and send the wrong signals to users.
Dealloc::
Py_TYPE(self)->tp_free((PyObject *)self);
becomes::
PyTypeObject *type = Py_GetType(self);
type->tp_free((PyObject *)self);
Py_DECREF(type);
Size::
res = _PyObject_SIZE(Py_TYPE(self)) + self->allocated *
self->ob_descr->itemsize;
becomes::
PyTypeObject *type = Py_GetType(self);
res = _PyObject_SIZE(type) + self->allocated * self->ob_descr->itemsize;
Py_DECREF(type);
Error::
PyErr_Format(PyExc_TypeError,
"first argument must be a type object, not %.200s",
Py_TYPE(arraytype)->tp_name);
becomes::
PyErr_Format(PyExc_TypeError,
"first argument must be a type object, not %T",
arraytype);
Py_BuildValue::
result = Py_BuildValue(
"N(CO)O", Py_GetType(self), typecode, list, dict);
becomes::
result = Py_BuildValue(
"N(CO)O", Py_GetType(self), typecode, list, dict);
Victor