[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