Convert static initializers of `PyTypeObject`s to use C99 Designated (named) initializers
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 77.2k
- Forks
- 35.9k
- PR merge metrics
- PR metrics pending
Description
Named initializer are both easier to read and less error prone. There is AFAICT no downside to using them.
However, we have been historically reluctant to change code for purely maintenance. Personally, I think this leads to poorer code quality, but others value cleaner code history more.
In this case I think the readability and correctness advantages are such that we should make this change and accept the inconvenience in version control history.
As a motivating example, take the bool type, PyBool_Type:
PyTypeObject PyBool_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
"bool",
offsetof(struct _longobject, long_value.ob_digit), /* tp_basicsize */
sizeof(digit), /* tp_itemsize */
bool_dealloc, /* tp_dealloc */
0, /* tp_vectorcall_offset */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_as_async */
bool_repr, /* tp_repr */
&bool_as_number, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
bool_doc, /* tp_doc */
0, /* tp_traverse */
0, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
0, /* tp_getset */
&PyLong_Type, /* tp_base */
0, /* tp_dict */
0, /* tp_descr_get */
0, /* tp_descr_set */
0, /* tp_dictoffset */
0, /* tp_init */
0, /* tp_alloc */
bool_new, /* tp_new */
.tp_vectorcall = bool_vectorcall,
};
There are a lot of zeros, and a lot of comments to make sure we have the right number of zeros. If one is missing, things go wrong.
Contrast that with the C99 version:
PyTypeObject PyBool_Type = {
PyVarObject_HEAD_INIT(&PyType_Type, 0)
.tp_name = "bool",
.tp_basicsize = offsetof(struct _longobject, long_value.ob_digit),
.tp_itemsize = sizeof(digit),
.tp_flags = Py_TPFLAGS_DEFAULT,
.tp_as_number = &bool_as_number,
.tp_base = &PyLong_Type,
.tp_dealloc = bool_dealloc,
.tp_doc = bool_doc,
.tp_new = bool_new,
.tp_repr = bool_repr,
.tp_vectorcall = bool_vectorcall,
};
The code is self describing (no need for comments naming the fields) and is much less error prone. The fields can listed in any order, in this case with the core field first, then the optional fields alphabetically.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by locating PyBool_Type and the other static PyTypeObject initializers in the CPython source, then compare their field order with the PyTypeObject definition. Convert the initializers to C99 designated fields while preserving their values; done means the affected code builds successfully with the new initializer syntax.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- backend
- Issue type
- Refactor
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100