[Python-Dev] PEP 580/590 discussion
Mark Shannon
mark at hotpy.org
Sat Apr 27 08:07:25 EDT 2019
Hi Jeroen,
On 25/04/2019 3:42 pm, Jeroen Demeyer wrote:
> On 2019-04-25 00:24, Petr Viktorin wrote:
>> I believe we can achieve
>> that by having PEP 590's (o+offset) point not just to function pointer,
>> but to a {function pointer; flags} struct with flags defined for two
>> optimizations:
>
> What's the rationale for putting the flags in the instance? Do you
> expect flags to be different between one instance and another instance
> of the same class?
>
>> Both type flags and
>> nargs bits are very limited resources.
>
> Type flags are only a limited resource if you think that all flags ever
> added to a type must be put into tp_flags. There is nothing wrong with
> adding new fields tp_extraflags or tp_vectorcall_flags to a type.
>
>> What I don't like about it is that it has
>> the extensions built-in; mandatory for all callers/callees.
>
> I don't agree with the above sentence about PEP 580:
> - callers should use APIs like PyCCall_FastCall() and shouldn't need to
> worry about the implementation details at all.
> - callees can opt out of all the extensions by not setting any special
> flags and setting cr_self to a non-NULL value. When using the flags
> CCALL_FASTCALL | CCALL_KEYWORDS, then implementing the callee is exactly
> the same as PEP 590.
>
>> As in PEP 590, any class that uses this mechanism shall not be usable as
>> a base class.
>
> Can we please lift this restriction? There is really no reason for it.
> I'm not aware of any similar restriction anywhere in CPython. Note that
> allowing subclassing is not the same as inheriting the protocol. As a
> compromise, we could simply never inherit the protocol.
AFAICT, any limitations on subclassing exist solely to prevent tp_call
and the PEP 580/590 function pointer being in conflict. This limitation
is inherent and the same for both PEPs. Do you agree?
Let us conside a class C that sets the
Py_TPFLAGS_HAVE_CCALL/Py_TPFLAGS_HAVE_VECTORCALL flag.
It will set the function pointer in a new instance, C(), when the object
is created. If we create a new class D:
class D(C):
__call__(self, ...):
...
and then create an instance `d = D()` then calling d will have two
contradictory behaviours; the one installed by C in the function pointer
and the one specified by D.__call__
We can ensure correct behaviour by setting the function pointer to NULL
or a forwarding function (depending on the implementation) if __call__
has been overridden. This would be enforced at class creation/readying time.
Cheers,
Mark.
More information about the Python-Dev
mailing list