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.
_______________________________________________
Python-Dev mailing list
Python-Dev@python.org
https://mail.python.org/mailman/listinfo/python-dev
Unsubscribe:
https://mail.python.org/mailman/options/python-dev/archive%40mail-archive.com