[Python-Dev] PEP 590 discussion

Petr Viktorin encukou at gmail.com
Thu Apr 11 07:21:49 EDT 2019


On 4/11/19 1:05 AM, Jeroen Demeyer wrote:
> On 2019-04-10 18:25, Petr Viktorin wrote:
>> Hello!
>> I've had time for a more thorough reading of PEP 590 and the reference
>> implementation. Thank you for the work!
> 
> And thank you for the review!

One general note: I am not (yet) choosing between PEP 580 and PEP 590.
I am not looking for arguments for/against whole PEPs, but individual 
ideas which, I believe, can still be mixed & matched.

I see the situation this way:
- I get about one day per week when I can properly concentrate on 
CPython. It's frustrating to be the bottleneck.
- Jeroen has time, but it would frustrating to work on something that 
will later be discarded, and it's frustrating to not be able to move the 
project forward.
- Mark has good ideas, but seems to lack the time to polish them, or 
even test out if they are good. It is probably frustrating to see 
unpolished ideas rejected.

I'm looking for ways to reduce the frustration, given where we are.


Jeroen, thank you for the comments. Apologies for not having the time to 
reply to all of them properly right now.

Mark, if you could find the time to answer (even just a few of the 
points), it would be great. I ask you to share/clarify your thoughts, 
not defend your PEP.


>> I'd now describe the fundamental
>> difference between PEP 580 and PEP 590 as:
>> - PEP 580 tries to optimize all existing calling conventions
>> - PEP 590 tries to optimize (and expose) the most general calling
>> convention (i.e. fastcall)
> 
> And PEP 580 has better performance overall, even for METH_FASTCALL. See 
> this thread:
> https://mail.python.org/pipermail/python-dev/2019-April/156954.html
> 
> Since these PEPs are all about performance, I consider this a very 
> relevant argument in favor of PEP 580.
>
>> PEP 580 also does a number of other things, as listed in PEP 579. But I
>> think PEP 590 does not block future PEPs for the other items.
>> On the other hand, PEP 580 has a much more mature implementation -- and
>> that's where it picked up real-world complexity.
> About complexity, please read what I wrote in
> https://mail.python.org/pipermail/python-dev/2019-March/156853.html
> 
> I claim that the complexity in the protocol of PEP 580 is a good thing, 
> as it removes complexity from other places, in particular from the users 
> of the protocol (better have a complex protocol that's simple to use, 
> rather than a simple protocol that's complex to use).

Sadly, I need more time on this than I have today; I'll get back to it 
next week.

> As a more concrete example of the simplicity that PEP 580 could bring, 
> CPython currently has 2 classes for bound methods implemented in C:
> - "builtin_function_or_method" for normal C methods
> - "method-descriptor" for slot wrappers like __eq__ or __add__
> 
> With PEP 590, these classes would need to stay separate to get maximal 
> performance. With PEP 580, just one class for bound methods would be 
> sufficient and there wouldn't be any performance loss. And this extends 
> to custom third-party function/method classes, for example as 
> implemented by Cython.
> 
>> PEP 590's METH_VECTORCALL is designed to handle all existing use cases,
>> rather than mirroring the existing METH_* varieties.
>> But both PEPs require the callable's code to be modified, so requiring
>> it to switch calling conventions shouldn't be a problem.
> 
> Agreed.
> 
>> Jeroen's analysis from
>> https://mail.python.org/pipermail/python-dev/2018-July/154238.html seems
>> to miss a step at the top:
>>
>> a. CALL_FUNCTION* / CALL_METHOD opcode
>>        calls
>> b. _PyObject_FastCallKeywords()
>>        which calls
>> c. _PyCFunction_FastCallKeywords()
>>        which calls
>> d. _PyMethodDef_RawFastCallKeywords()
>>        which calls
>> e. the actual C function (*ml_meth)()
>>
>> I think it's more useful to say that both PEPs bridge a->e (via
>> _Py_VectorCall or PyCCall_Call).
> 
> Not quite. For a builtin_function_or_method, we have with PEP 580:
> 
> a. call_function()
>      calls
> d. PyCCall_FastCall
>      which calls
> e. the actual C function
> 
> and with PEP 590 it's more like:
> 
> a. call_function()
>      calls
> c. _PyCFunction_FastCallKeywords
>      which calls
> d. _PyMethodDef_RawFastCallKeywords
>      which calls
> e. the actual C function
> 
> Level c. above is the vectorcall wrapper, which is a level that PEP 580 
> doesn't have.

Again, I'll get back to this next week.

>> The way `const` is handled in the function signatures strikes me as too
>> fragile for public API.
> 
> That's a detail which shouldn't influence the acceptance of either PEP.

True.
I guess what I want from the answer is to know how much thought went 
into const handling: is what's in the PEP an initial draft, or does it 
solve some hidden issue?

>> Why not have a per-type pointer, and for types that need it (like
>> PyTypeObject), make it dispatch to an instance-specific function?
> 
> That would be exactly https://bugs.python.org/issue29259
> 
> I'll let Mark comment on this.
> 
>> Minor things:
>> - "Continued prohibition of callable classes as base classes" -- this
>> section reads as a final. Would you be OK wording this as something
>> other PEPs can tackle?
>> - "PyObject_VectorCall" -- this looks extraneous, and the reference
>> imlementation doesn't need it so far. Can it be removed, or justified?
>> - METH_VECTORCALL is *not* strictly "equivalent to the currently
>> undocumented METH_FASTCALL | METH_KEYWORD flags" (it has the
>> ARGUMENTS_OFFSET complication).
>> - I'd like to officially call this PEP "Vectorcall", see
>> https://github.com/python/peps/pull/984
> 
> Those are indeed details which shouldn't influence the acceptance of 
> either PEP. If you go with PEP 590, then we should discuss this further.

Here again, I mostly want to know if the details are there for deeper 
reasons, or just points to polish.

>> Mark, what are your plans for next steps with PEP 590? If a volunteer
>> wanted to help you push this forward, what would be the best thing to
>> work on?
> 
> Personally, I think what we need now is a decision between PEP 580 and 
> PEP 590 (there is still the possibility of rejecting both but I really 
> hope that this won't happen). There is a lot of work that still needs to 
> be done after either PEP is accepted, such as:
> - finish and merge the reference implementation
> - document everything
> - use the protocol in more classes where it makes sense (for example, 
> staticmethod, wrapper_descriptor)
> - use this in Cython
> - handle more issues from PEP 579
> 
> I volunteer to put my time into this, regardless of which PEP is 
> accepted. Of course, I still think that PEP 580 is better, but I also 
> want this functionality even if PEP 590 is accepted.

Thank you. Sorry for the way this is dragged out.
Would it help to set some timeline/deadlines here?

>> Jeroen, is there something in PEPs 579/580 that PEP 590 blocks, or
>> should address?
> 
> Well, PEP 580 is an extensible protocol while PEP 590 is not. But, 
> PyTypeObject is extensible, so even with PEP 590 one can always extend 
> that (for example, PEP 590 uses a type flag Py_TPFLAGS_METHOD_DESCRIPTOR 
> where PEP 580 instead uses the structs for the C call protocol). But I 
> guess that extending PyTypeObject will be harder to justify (say, in a 
> future PEP) than extending the C call protocol.

Thanks. I also like PEP 580's extensibility.

> Also, it's explicitly allowed for users of the PEP 580 protocol to 
> extend the PyCCallDef structure with custom fields. But I don't have a 
> concrete idea of whether that will be useful.

I don't have good general experience with premature extensibility, so 
I'd not count this as a plus.


More information about the Python-Dev mailing list