[Types-sig] Re: Meta-classes discussion starter

Guido van Rossum guido@CNRI.Reston.VA.US
Mon, 30 Nov 1998 14:35:18 -0500


> I did intend my thread to be related to the types/classes discussion.  Many
> of the threads in the archive seem to eventually come around to the idea
> that if everything is to be an object and have a class (the whole
> unification thing), then classes must have classes, and to be really tidy
> and orthogonal, these meta-classes should be well-defined as such (Rather
> than, say, simply declaring the class of every class to be an empty built-in
> object MetaClass whose class is itself, and leaving it at that).
> 
> Given the premise that meta-classes should be to classes as classes
> currently are to instances, I see two problems.   How do you deal with
> method binding? How do you define methods at different levels
> (meta-/class/instance) with the same name?  These are particularly a problem
> if you want to initialize your classes and instances with __init__.
> Meta-classes need a way to spell "__init__ for my classes" and "__init__ for
> instances of my classes", and "__init__ for my classes" *has* to be a class
> method if it is to exist.

Have you read my post "ASCII art" in the python-classes@egroups.com
mailing list?  It's very relevant.  I'll repeat it here, because it's
such a drag to dig it out of the egroups archives (and their HTML
screws up the ASCII art!).  But you should still read that group's
archives, at http://www.egroups.com/list/python-classes/.

------------------------------ repost ------------------------------

Subject: [python-classes] ASCII art
From: Guido van Rossum <guido@CNRI.Reston.VA.US>
To: python-classes@egroups.com
Date: Tue, 27 Oct 1998 19:08:14 -0500

I've been working on a response for days now, and I'm giving up.
Instead, I'll try to draw some stuff that I drew on a whiteboard today 
in front of a bunch of Norwegian and local Pythoneers.

Consider instance x of class C, derived from class B.  This is the
ideal diagram:

        +-----------+
        |     x     |
        +-----------+
              |
              |
              v
        +-----------+     +-----------+
        |     C     |---->|     B     |
        +-----------+     +-----------+
                \             /
                 \           /
                  v         v
                 +-----------+
                 |   class   |
                 +-----------+

I use the following convention: an arrow pointing down goes from an
object to its meta-object, class or type.  An arrow pointing right
goes from a class to its base class.

The idea is that you follow the down arrow to get to an object's
behavior -- so x's behavior comes from C, and C's behavior comes from
'class' (and so does B's).  You follow the arrow right to delegate
attributes to a base class.  (With multiple inheritance, you draw
multipl arrows.)  Note that the delegation from C to B will allow x to 
find behavior in B if it isn't found in C.

In the current CPython implementation, things look a bit different:

                        +-----------+
                        |     x     |
                        +-----------+
                         /    |
                        /     |
                       /      v
                      / +-----------+     +-----------+
                     /  |     C     |---->|     B     |
                    /   +-----------+     +-----------+
                   v            \             /
        *===========*            \           /
        I instance  I             v         v
        *===========*            *===========*
                  \              I   class   I
                   \             *===========*
                    \            /
                     \          /
                      v        v
                    *===========*
                    I   type    I
                    *===========*

That is, x has *two* behavior-defining links: one to the type
'instance', one to the class C.  (I've drawn type objects in a
different style here.)  This is what causes a lot of grief.

I'd like to move to the first diagram.  It can be extended downwards
and to the right.  You could have as many levels of metaclasses as you
want, and it would all be well defined: behavior comes from below,
delegated behavior from the right.

I've got to go soon, and I want this to go out tonight, so I'll just
add some quick notes.

- I like David's idea of specifying the metaclass in the class
statement.  Specifying the base class is specifying the arrow to the
right; specifying the metaclass is specifying the arrow down.

- There is a difference between class methods (which specify behavior
of the class, and are defined in the metaclass) and C++/Java style
static methods (which should be defined in the class using a special
syntax so that they don't belong to a specific instance; however, as
in C++/Java, it should still be *possible* to invoke them via the
instance, as well as via the class.)  [I had a longer rant about this,
but no time to condense it now.]

- There could be a class "Object" which is used as the default right
arrow.

- There could also be a class "Turtles-all-the-way-down" which is used 
as the default arrow down.

- I don't know if Object and Turtles are the same object.  I know that
each has a right arrow to Object and each has a down arrow to Turtles;
they *could* be related like this:


      -------    ---------       ------------------
      |     |    |        \      |                |
      |     v    v         \     |                |
      |    +---------+      \    \->+--------+    |
      |    | Turtles |------------->| Object |---/
      |    +---------+        \     +--------+
      |          |             \         |
      \          /              \        /
       ----------                --------

(Heh! :-)

- There are plenty of problems left.  Later, after my drumming class :-)

--Guido van Rossum (home page: http://www.python.org/~guido/)