[Python-Dev] Classes and Metaclasses in Smalltalk

Guido van Rossum guido@digicool.com
Thu, 03 May 2001 09:26:22 -0500


> We are actually trying to turn classes into types here :-)

Yes!  Wait till you see my next batch of checkins. :-)

> Really, I think that we could resolve this issue by not inheriting
> from meta-classes. DictType is a creation of the meta-class
> TypeType. I'm not calling these instances to prevent additional
> confusion. The root of the problem is that for some reason there
> is belief that DictType should implicitly inherit attributes and 
> methods from TypeType. If we simply say that there is no implicit
> inheritance (only explicit one), then these problems should go
> away.

Sorry, you still seem to be confused about this.  As I tried to
explain before, DictType does not *inherit* from TypeType, but it is
an *instance* of TypeType.  TypeType defines a __repr__() method for
all its instances.  This is needed so that repr(DictType) returns
"<type 'DictType'>".  It is *not* inherited from TypeType!

If DictType were to inherit from something, it would inherit from the
(not yet existing) ObjectType.  ObjectType would have a __repr__
method too: it returns "<foo object at 0x......>".

But this method is overridden by DictType, so doesn't come into play.

Requiring explicit inheritance (whatever that may be) won't fix the
problem.

> Some of these ideas are burried in the "super" part of this 
> thread. Unfortunately this concept doesn't go very far since
> Python has multiple inheritance and thus the term "super"
> (referring to the class' single base class) is not well-defined.

Not true.  While super can't always refer to a single class, the use
of super can be completely well-defined in an unambiguous way.  Given

  class D(A, B, C):
    def foo(self):
      super.foo(self)

"super.foo" is whatever would be called in D1 if we changed the class
hierarchy as follows:

  class D1(A, B, C): pass
  class D(D1):
    def foo(self):
      D1.foo(self)

The problem with super is not that it isn't well-defined.  Its problem
is that it's not enough to do what you want.  In some situations
involving multiple inheritance, it can be essential to be able to
"merge" methods of the sane name defined in each of the base classes,
e.g.

  class C(A, B):
    def save(self):
      A.save(self)
      B.save(self)

So we can't use super as an argument to abandon explicitly naming the
base class of base methods.  Out of the proposed spellings that I can
remember:

      B.save(self)			# current Python
      B.__dict__['save'](self)		# ditto, butt ugly
      B::save(self)			# C++
      B._.save(self)			# Don Beaudry
      B.instanceMethods.save(self)	# ???

I still like current Python best!

> As Jim mentioned in his reply to Thomas' question, SmallTalk
> has two parallel hierarchies. One for the classes and one for
> the meta-classes. If we follow the same path in Python and
> keep the two well separated, I think we can resolve many of
> the issues which are currently showing up.

Yeah, but this is not the path that Python has already taken (and
which has been beaten further by Jim Fulton's ExtensionClasses).
Python's path is "turtles all the way down".  See also my old
head-exploding metaclasses paper.

> To link the two hierarchies together we don't need a "super"
> concept, but instead a way to reach the meta-class in charge
> of a class, say "klass.__creator__". 

Your confusion between the "isInstanceOf" and "isInheritedFrom"
relationships seems really deep!  Super relates to inheritance.
Metaclasses relate to instantiation (of the class, as an instance of
the metaclass).

> Note that there's another issue hiding in all this and again
> this is due to multiple inheritance: which meta-class is in
> charge of a class which is derived from two classes having
> different meta-classes ?
> 
> meta1            -->         o klass1
>                                o klass1a
>                                o klass1b
> meta2            -->         o klass2
>                                o klass2a
>                                o klass2b
> 
> class klass3(klass1a, klass2b):
>       ...                  
> 
> I think there's no clean way to resolve this, so I'd suggest
> to simply rule this out and declare it illegal (class can
> only be based on classes having the same meta-class).

Unfortunately, again thanks to Jim Fulton, we can't rule this out,
because this is actually used by ExtensionClasses.  The rule (as I
interpret it) gives the first base class control; if the first base
class is a standard class, it looks if any of the other base classes
are not standard classes, and if so, gives control to the first such
base class.  Another way to say this is that the first base class that
has a non-standard metaclass gets control.

(ExtensionClasses implements an additional rule where it requires all
except one of the base classes to define no instance variables.  This
is an example of the importance of metaclasses done right: the
metaclass has control over such issues.  I don't think that
Smalltalk's metaclasses have this much control -- you pretty much have
a 1-1 correspondence between class and metaclass.

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