On 2019-09-12, Petr Viktorin wrote:
With PEP 573, you don't need
PyType_DefiningTypeFromSlotFunc()
for normal methods. It's there for slots. For example, addition (nb_add) calls the C function:typedef PyObject * (*binaryfunc)(PyObject *left, PyObject *right);
There's no space to pass a PyFunction object, or any other object, to this directly. PEP 573 *gives up* on solving the problem, but documents the least bad solution that's available now, and gives you the PyType_DefiningTypeFromSlotFunc helper since it's not trivial to write.
Slots like np_add could lookup the PyFunction analog and call it. That object has the reference to the module namespace, just like a PyFunction object does. When the module is first created, you allocate heap objects for each of the PyFunction object thingies and bind them to the module. I believe this could (eventually) greatly simplify typeobject.c.
Most of the CPython runtime should not have to care if a function is implemented using bytecode or is implemented in C. The way things are organized now, there a lot of differences. Over time, I would prefer we make those two things more similar rather than more different. I see the PEP 573 an expedient solution but not an elegant one.
Performance of my proposed approach is a potential issue. Having nb_add point to a C function that directly implements the add operation is more efficient than looking up a PyFunction like thing (maybe from tp_dict, not sure) and then calling that. However, by making these things look the same, I believe you would remove a slew of special cases and branches within the CPython runtime and maybe preformance is as good or better. For types with an immutable nb_add slot, you could JIT the machine code for the nb_add slot and avoid the dynamic lookup of the PyFunction thingy.