@@ -17,8 +17,12 @@ Abstract
1717Replace type and module slots with a new, more type-safe structure that allows
1818adding new slots in a more forward-compatible way.
1919
20+ API added in 3.15 (:external+py3.15:c:func: `PyModule_FromSlotsAndSpec ` and the
21+ new :external+py3.15:ref: `extension export hook <extension-export-hook >`)
22+ will be changed to use the new slots.
23+
2024The existing slot structures and related API is soft-deprecated.
21- (That is: it will continue to work without warnings, and it’ll be fully
25+ (That is: they will continue to work without warnings, and it’ll be fully
2226documented and supported, but we plan to not add any new features to it.)
2327
2428
@@ -43,10 +47,10 @@ structure of the object to stay opaque (in both the API and the ABI),
4347allowing future CPython versions (or even alternative implementations) to
4448change the details.
4549
46- Both structures contain a *slots * field – essentially an array of
47- `tagged unions <https://en.wikipedia.org/wiki/Tagged_union >`__,
48- which allows for future expansion .
49- (In practice, slots are `` void `` pointers taged with an `` int `` ID.)
50+ Both structures contain a *slots * field, essentially an array of
51+ `tagged unions <https://en.wikipedia.org/wiki/Tagged_union >`__
52+ (`` void `` pointers taged with an `` int `` ID) .
53+ This allows for future expansion.
5054
5155In :pep: `793 `, new module creation API was added.
5256Instead of the ``PyModuleDef `` structure, it uses only an array of *slots *.
@@ -75,7 +79,7 @@ Type safety
7579 but is technically undefined or implementation-defined behaviour in C.
7680
7781 For example: :c:macro: `Py_tp_doc ` marks a string; :c:macro: `Py_mod_gil `
78- an integer, and :c:macro: `Py_tp_repr ` a function; all must
82+ a small integer, and :c:macro: `Py_tp_repr ` a function; all must
7983 be cast to ``void* ``.
8084
8185Limited forward compatibility
@@ -140,6 +144,8 @@ near future, users could add it with an "``OPTIONAL``" flag, making their class
140144support the ``@ `` operator only on CPython versions with that operator.
141145
142146
147+ .. _pep820-rationale :
148+
143149Rationale
144150=========
145151
@@ -205,9 +211,9 @@ This complicates slot handling inside the interpreter, but allows:
205211
206212- Mixing dynamically allocated (or stack-allocated) slots with ``static `` ones.
207213 This solves the issue that lead to the ``PyType_From* `` family of
208- functions expanding with values that typically can't be ``static ``
209- (i.e. it's often a symbol from another DLL, which can't be `` static ` `
210- data on Windows) .
214+ functions expanding with values that typically can't be ``static ``.
215+ For example, the * module * argument to :c:func: ` PyType_FromModuleAndSpec `
216+ should be a heap-allocated module object .
211217- Sharing a subset of the slots to implement functionality
212218 common to several classes/modules.
213219- Easily including some slots conditionally, e.g. based on the Python version.
@@ -228,23 +234,21 @@ and only use the “new” slots if they need any new features.
228234Fixed-width integers
229235---------------------
230236
231- This proposal uses fixed-width integers (``uint16_t ``), for slot IDs and
237+ This proposal uses fixed-width integers (``uint16_t ``) for slot IDs and
232238flags.
233- With the C ``int `` type, using more that 16 bits would not be portable,
239+ With the C ``int `` type, using more than 16 bits would not be portable,
234240but it would silently work on common platforms.
235241Using ``int `` but avoiding values over ``UINT16_MAX `` wastes 16 bits
236242on common platforms.
237243
238- With these defined as ``uint16_t ``, it seems natural to use fixed-width
239- integers for everything except pointers and sizes.
240244
241245Memory layout
242246-------------
243247
244248On common 64-bit platforms, we can keep the size of the new struct the same
245249as the existing ``PyType_Slot `` and ``PyModuleDef_Slot ``. (The existing
246250struct waste 6 out of 16 bytes due to ``int `` portability and padding;
247- this proposal puts those bits to use for new features.)
251+ this proposal puts some of those bits to use for new features.)
248252On 32-bit platforms, this proposal calls for the same layout as on 64-bit,
249253doubling the size compared to the existing structs (from 8 bytes to 16).
250254For “configuration” data that's usually ``static ``, it should be OK.
@@ -283,6 +287,27 @@ The main disadvantage is that any internal lookup tables will be either bigger
283287or harder to manage (if they're merged).
284288
285289
290+ Deprecation warnings
291+ --------------------
292+
293+ Multiple slots are documented to not allow NULL values, but CPython allows
294+ NULL for backwards compatibility.
295+ Similarly, multiple slot IDs should not appear more than once in a single
296+ array, but CPython allows such duplicates.
297+
298+ This is a maintenance issue, as CPython should preserve its undocumented
299+ (and often untested) behaviour in these cases as the implementation is changed.
300+
301+ It also prevents API extensions.
302+ For example, instead of adding the :c:macro: `Py_TPFLAGS_DISALLOW_INSTANTIATION `
303+ flag in 3.10, we could have allowed settning the ``Py_tp_new `` slot to NULL for
304+ the same effect.
305+
306+ To allow changing the edge case behaviour in the (far) future,
307+ and to allow freedom for possible alternative implementations of the C API,
308+ we'll start issuing runtime deprecation warnings in these cases.
309+
310+
286311Specification
287312=============
288313
@@ -311,20 +336,33 @@ A new ``PySlot`` structure will be defined as follows::
311336- An union with the data, whose type depends on the slot.
312337
313338
314- Functions that use slots
315- ------------------------
339+ New API
340+ -------
316341
317342The following function will be added.
318343It will create the corresponding Python type object from the given
319344array of slots::
320345
321346 PyObject *PyType_FromSlots(const PySlot *slots);
322347
348+ With this function, the ``Py_tp_token `` slot may not be set to
349+ ``Py_TP_USE_SPEC `` (i.e. ``NULL ``).
350+
351+
352+ Changed API
353+ -----------
354+
323355The ``PyModule_FromSlotsAndSpec `` function (added in CPython 3.15 in
324356:pep: `793 `) will be *changed * to take the new slot structure::
325357
326358 PyObject *PyModule_FromSlotsAndSpec(const PySlot *slots, PyObject *spec)
327359
360+ The :external+py3.15:ref: `extension module export hook <extension-export-hook >`
361+ added in :pep: `793 ` (:samp: `PyModExport_{ <name> } `) will be *changed * to
362+ return the new slot structure.
363+ The :external+py3.15:c:macro: `PyMODEXPORT_FUNC ` macro will
364+ be updated accordingly.
365+
328366
329367General slot semantics
330368----------------------
@@ -354,7 +392,7 @@ Flags
354392 This flag is implied for function pointers.
355393
356394 The flag applies even to data the slot points to "indirectly", except for
357- nested slots -- see `` Py_slot_subslots ` ` below -- which can have their
395+ nested slots -- see :ref: ` pep820-nested-tables ` below -- which can have their
358396 own ``PySlot_STATIC `` flag.
359397 For example, if applied to a ``Py_tp_members `` slot that points to an
360398 *array * of ``PyMemberDef `` structures, then the entire array, as well as the
@@ -371,7 +409,7 @@ Flags
371409 If the entire block is to be optional, it should end with a
372410 slot with the OPTIONAL flag.
373411
374- - ``PySlot_IS_PTR ``: The data is stored in ``sl_ptr ``, and must be cast to
412+ - ``PySlot_INTPTR ``: The data is stored in ``sl_ptr ``, and must be cast to
375413 the appropriate type.
376414
377415 This flag simplifies porting from the existing ``PyType_Slot `` and
@@ -404,14 +442,18 @@ The following macros will be added to the API to simplify slot definition::
404442 #define PySlot_END {0}
405443
406444We'll also add two more macros that avoid named initializers,
407- for use in C++11-compatibile code::
445+ for use in C++11-compatibile code.
446+ Note that these cast the value to ``void* ``, so they do not improve type safety
447+ over existing slots::
408448
409449 #define PySlot_PTR(NAME, VALUE) \
410- {NAME, PySlot_IS_PTR , {0}, {(void*)(VALUE)}}
450+ {NAME, PySlot_INTPTR , {0}, {(void*)(VALUE)}}
411451
412452 #define PySlot_PTR_STATIC(NAME, VALUE) \
413- {NAME, PySlot_IS_PTR|Py_SLOT_STATIC, {0}, {(void*)(VALUE)}}
453+ {NAME, PySlot_INTPTR|Py_SLOT_STATIC, {0}, {(void*)(VALUE)}}
454+
414455
456+ .. _pep820-nested-tables :
415457
416458Nested slot tables
417459------------------
@@ -427,7 +469,7 @@ Two more slots will allow similar nesting for existing slot structures:
427469- ``Py_mod_slots `` for an array of ``PyModuleDef_Slot ``
428470
429471Each ``PyType_Slot `` in the array will be converted to
430- ``(PySlot){.sl_id=slot, .sl_flags=PySlot_IS_PTR , .sl_ptr=func} ``,
472+ ``(PySlot){.sl_id=slot, .sl_flags=PySlot_INTPTR , .sl_ptr=func} ``,
431473and similar with ``PyModuleDef_Slot ``.
432474
433475The initial implementation will have restrictions that may be lifted
@@ -437,8 +479,6 @@ in the future:
437479 ``PySlot_HAS_FALLBACK `` (the flag cannot be set on them nor a slot that
438480 precedes them).
439481- Nesting depth will be limited to 5 levels.
440- (4 levels for the existing ``PyType_From* ``, ``PyModule_From* `` functions,
441- which will use up one level internally.)
442482
443483
444484New slot IDs
@@ -454,8 +494,9 @@ definitions, will be added:
454494 allowed with ``Py_slot_end ``.
455495
456496- ``Py_slot_subslots ``, ``Py_tp_slots ``, ``Py_mod_slots ``: see
457- *Nested slot tables * above
458- - ``Py_slot_invalid ``: treated as an unknown slot ID.
497+ :ref: `pep820-nested-tables ` above
498+ - ``Py_slot_invalid `` (defined as ``UINT16_MAX ``, i.e. ``-1 ``): treated as an
499+ unknown slot ID.
459500
460501The following new slot IDs will be added to cover existing
461502members of ``PyModuleDef ``:
@@ -483,6 +524,9 @@ Specifying both in a single definition will be deprecated (currently,
483524None of the new slots will be usable with ``PyType_GetSlot ``.
484525(This limitation may be lifted in the future, with C API WG approval.)
485526
527+ Of the new slots, only ``Py_slot_end ``, ``Py_slot_subslots ``, ``Py_tp_slots ``,
528+ ``Py_mod_slots `` will be allowed in ``PyType_Spec `` and/or ``PyModuleDef ``.
529+
486530
487531Slot renumbering
488532----------------
@@ -496,7 +540,7 @@ Slots numbered 1 through 4 (``Py_bf_getbuffer``...\ ``Py_mp_length`` and
496540The old numbers will remain as aliases, and will be used when compiling for
497541Stable ABI versions below 3.15.
498542
499- Slots for members of ``PyType_Spec ``, which were added in
543+ Slots for members of ``PyModuleDef ``, which were added in
500544:ref: `PEP 793 <pep793-api-summary >`, will be renumbered so that they have
501545unique IDs:
502546
@@ -532,10 +576,48 @@ in this PEP.
532576This includes nested "new-style" slots (``Py_slot_subslots ``).
533577
534578
579+ .. _pep820-hard-deprecations :
580+
581+ Deprecation warnings
582+ --------------------
583+
584+ CPython will emit runtime deprecation warnings for the following cases,
585+ for slots where the case is currently disallowed in documentation but allowed
586+ by the runtime:
587+
588+ - setting a slot value to NULL:
589+
590+ - all type slots except ``Py_tp_doc ``
591+ - ``Py_mod_create ``
592+ - ``Py_mod_exec ``
593+
594+ - repeating a slot ID in a single slots array (including sub-slot arrays
595+ added in this PEP):
596+
597+ - all type slots, except slots where this is already a runtime error
598+ (``Py_tp_doc ``, ``Py_tp_members ``)
599+ - ``Py_mod_create ``
600+ - ``Py_mod_abi ``
601+
602+
535603Backwards Compatibility
536604=======================
537605
538- This PEP only adds APIs, so it's backwards compatible.
606+ This PEP proposes to change API that was already released in alpha versions of
607+ Python 3.15.
608+ This will inconvenience early adopters of that API, but -- as long as the
609+ PEP is accepted and implemented before the first bety -- this change is within
610+ the letter and spirit of our backwards compatibility policy.
611+
612+ Renumbering of slots is done in a backwards-compatible way.
613+ Old values continue to be accepted, and are used when compiling for
614+ earlier Stable ABI.
615+
616+ Some cases that are documented as illegal will begin emitting deprecation
617+ warnings (see :ref: `pep820-hard-deprecations `).
618+
619+ Otherwise, this PEP only adds and soft-deprecates APIs, which is backwards
620+ compatible.
539621
540622
541623Security Implications
@@ -553,13 +635,32 @@ Adjust the "Extending and Embedding" tutorial to use this.
553635Reference Implementation
554636========================
555637
556- None yet.
638+ Draft implementation is available as `pull request #37 in the author's fork
639+ <https://github.com/encukou/cpython/pull/37> `__.
557640
558641
559642Rejected Ideas
560643==============
561644
562- None yet.
645+ See the :ref: `pep820-rationale ` section for several alternative ideas.
646+
647+ Third-party slot ID allocation
648+ ------------------------------
649+
650+ It was suggested to allow third parties to reserve slot IDs for their own use.
651+ This would be mainly useful for alternate implementations. For example,
652+ something like GraalPy might want custom type slots (e.g. an "inherits
653+ from this Java class" slot).
654+ Similarly, at one point PyPy had an extra ``tp_pypy_flags `` in their
655+ typeobject struct.
656+
657+ This PEP does not specify a namespace mechanism.
658+ One can be added in the future.
659+ We're also free to reserve individual slot IDs for alternate implementations.
660+
661+ Note that slots are not a good way for *extension modules * to add extra data
662+ to types or modules, as there is no API to retrieve the slots used to create
663+ a specific object.
563664
564665
565666Open Issues
@@ -568,6 +669,13 @@ Open Issues
568669None yet.
569670
570671
672+ Acknowledgements
673+ ================
674+
675+ Thanks to Da Woods and Antoine Pitrou for substantial input on this iteration
676+ of the proposal.
677+
678+
571679Copyright
572680=========
573681
0 commit comments