@@ -273,8 +273,28 @@ be an instance of a subclass.
273273.. note ::
274274 The explicit cast to ``CustomObject * `` above is needed because we defined
275275 ``Custom_dealloc `` to take a ``PyObject * `` argument, as the ``tp_dealloc ``
276- function pointer expects to receive a ``PyObject * `` argument. Otherwise,
277- this would result in an undefined behaviour at runtime!
276+ function pointer expects to receive a ``PyObject * `` argument.
277+ By assigning to the the ``tp_dealloc `` slot of a type, we declare
278+ that it can only be called with instances of our ``CustomObject ``
279+ class, so the cast to ``(CustomObject *) `` is safe.
280+ This is object-oriented polymorphism, in C!
281+
282+ In existing code, or in previous versions of this tutorial,
283+ you might see similar functions take a pointer to the subtype
284+ object structure (``CustomObject* ``) directly, like this::
285+
286+ Custom_dealloc(CustomObject *self)
287+ {
288+ Py_XDECREF(self->first);
289+ Py_XDECREF(self->last);
290+ Py_TYPE(self)->tp_free((PyObject *) self);
291+ }
292+ ...
293+ .tp_dealloc = (destructor) Custom_dealloc,
294+
295+ This does the same thing on all architectures that CPython
296+ supports, but according to the C standard, it invokes
297+ undefined behavior.
278298
279299We want to make sure that the first and last names are initialized to empty
280300strings, so we provide a ``tp_new `` implementation::
0 commit comments