[Python-checkins] CVS: python/nondist/peps pep-0253.txt,1.10,1.11
Guido van Rossum
gvanrossum@users.sourceforge.net
Wed, 11 Jul 2001 12:09:30 -0700
Update of /cvsroot/python/python/nondist/peps
In directory usw-pr-cvs1:/tmp/cvs-serv29387
Modified Files:
pep-0253.txt
Log Message:
Added a section on multiple inheritance.
Index: pep-0253.txt
===================================================================
RCS file: /cvsroot/python/python/nondist/peps/pep-0253.txt,v
retrieving revision 1.10
retrieving revision 1.11
diff -C2 -r1.10 -r1.11
*** pep-0253.txt 2001/07/10 20:46:24 1.10
--- pep-0253.txt 2001/07/11 19:09:28 1.11
***************
*** 283,287 ****
subsystem if the type supports garbage collection. This slot
exists so that derived types can override the memory allocation
! policy (e.g. which heap is being used) separately from the
initialization code. The signature is:
--- 283,287 ----
subsystem if the type supports garbage collection. This slot
exists so that derived types can override the memory allocation
! policy (like which heap is being used) separately from the
initialization code. The signature is:
***************
*** 369,375 ****
unregister the object with the garbage collection subsystem, and
can be overridden by a derived class; tp_dealloc() should
! deinitialize the object (e.g. by calling Py_XDECREF() for various
! sub-objects) and then call tp_free() to deallocate the memory.
! The signature for tp_dealloc() is the same as it always was:
void tp_dealloc(PyObject *object)
--- 369,376 ----
unregister the object with the garbage collection subsystem, and
can be overridden by a derived class; tp_dealloc() should
! deinitialize the object (usually by calling Py_XDECREF() for
! various sub-objects) and then call tp_free() to deallocate the
! memory. The signature for tp_dealloc() is the same as it always
! was:
void tp_dealloc(PyObject *object)
***************
*** 637,640 ****
--- 638,729 ----
+ Multiple Inheritance
+
+ The Python class statement supports multiple inheritance, and we
+ will also support multiple inheritance involving built-in types.
+
+ However, there are some restrictions. The C runtime architecture
+ doesn't make it feasible to have a meaningful subtype of two
+ different built-in types except in a few degenerate cases.
+ Changing the C runtime to support fully general multiple
+ inheritance would be too much of an upheaval of the code base.
+
+ The main problem with multiple inheritance from different built-in
+ types stems from the fact that the C implementation of built-in
+ types accesses structure members directly; the C compiler
+ generates an offset relative to the object pointer and that's
+ that. For example, the list and dictionary type structures each
+ declare a number of different but overlapping structure members.
+ A C function accessing an object expecting a list won't work when
+ passed a dictionary, and vice versa, and there's not much we could
+ do about this without rewriting all code that accesses lists and
+ dictionaries. This would be too much work, so we won't do this.
+
+ The problem with multiple inheritance is caused by conflicting
+ structure member allocations. Classes defined in Python normally
+ don't store their instance variables in structure members: they
+ are stored in an instance dictionary. This is the key to a
+ partial solution. Suppose we have the following two classes:
+
+ class A(dictionary):
+ def foo(self): pass
+
+ class B(dictionary):
+ def bar(self): pass
+
+ class C(A, B): pass
+
+ (Here, 'dictionary' is the type of built-in dictionary objects,
+ a.k.a. type({}) or {}.__class__ or types.DictType.) If we look at
+ the structure lay-out, we find that an A instance has the lay-out
+ of a dictionary followed by the __dict__ pointer, and a B instance
+ has the same lay-out; since there are no structure member lay-out
+ conflicts, this is okay.
+
+ Here's another example:
+
+ class X(object):
+ def foo(self): pass
+
+ class Y(dictionary):
+ def bar(self): pass
+
+ class Z(X, Y): pass
+
+ (Here, 'object' is the base for all built-in types; its structure
+ lay-out only contains the ob_refcnt and ob_type members.) This
+ example is more complicated, because the __dict__ pointer for X
+ instances has a different offset than that for Y instances. Where
+ is the __dict__ pointer for Z instances? The answer is that the
+ offset for the __dict__ pointer is not hardcoded, it is stored in
+ the type object.
+
+ Suppose on a particular machine an 'object' structure is 8 bytes
+ long, and a 'dictionary' struct is 60 bytes, and an object pointer
+ is 4 bytes. Then an X structure is 12 bytes (an object structure
+ followed by a __dict__ pointer), and a Y structure is 64 bytes (a
+ dictionary structure followed by a __dict__ pointer). The Z
+ structure has the same lay-out as the Y structure in this example.
+ Each type object (X, Y and Z) has a "__dict__ offset" which is
+ used to find the __dict__ pointer. Thus, the recipe for looking
+ up an instance variable is:
+
+ 1. get the type of the instance
+ 2. get the __dict__ offset from the type object
+ 3. add the __dict__ offset to the instance pointer
+ 4. look in the resulting address to find a dictionary reference
+ 5. look up the instance variable name in that dictionary
+
+ Of course, this recipe can only be implemented in C, and I have
+ left out some details. But this allows us to use multiple
+ inheritance patterns similar to the ones we can use with classic
+ classes.
+
+ XXX I should write up the complete algorithm here to determine
+ base class compatibility, but I can't be bothered right now. Look
+ at best_base() in typeobject.c in the implementation mentioned
+ below.
+
+
XXX To be done
***************
*** 644,658 ****
- mapping between type object slots (tp_foo) and special methods
! (__foo__)
- built-in names for built-in types (object, int, str, list etc.)
! - multiple inheritance restrictions
- __slots__
- the HEAPTYPE and DYNAMICTYPE flag bits
- API docs for all the new functions
--- 733,753 ----
- mapping between type object slots (tp_foo) and special methods
! (__foo__) (actually, this may belong in PEP 252)
- built-in names for built-in types (object, int, str, list etc.)
! - method resolution order
+ - __dict__
+
- __slots__
- the HEAPTYPE and DYNAMICTYPE flag bits
+ - GC support
+
- API docs for all the new functions
+
+ - high level user overview