[Python-Dev] Classes and Metaclasses in Smalltalk

M.-A. Lemburg mal@lemburg.com
Wed, 02 May 2001 11:09:17 +0200


Guido van Rossum wrote:
> 
> While implementing more class-like behavior for built-in types in the
> experimental descr-branch in the 2.2 CVS tree, I've noticed problems
> caused by Python's collapsing of class attributes and instance
> attributes.
> 
> For example, suppose d is a dictionary.  My experimental changes make
> d.__class__ return DictType (from the types module).
> (DictType.__class__ is TypeType, by the way.)  I also added special
> methods.  For example, d.__repr__() now returns repr(d).  I am
> preparing for subclassing of built-in types, so I will eventually be
> able to derive a class MyDictType from DictType, as follows:
> 
> class MyDictType(DictType):
>   ...
> 
> Now comes the fun part.  Suppose MyDictType wants to define its own
> repr():
> 
> class MyDictType(DictType):
>   def __repr__(self):
>     return "MyDictType(%s)" % DictType.__repr__(self)
> 
> But, (surprise, surprise!), DictType itself also has a __repr__()
> method: it returns the string "<type 'dictionary'>".
> 
> So the above code would fail: DictType.__repr__() returns
> repr(DictType), and DictType.__repr__(self) raises an argument count
> error.  The correct __repr__ method for dictionary objects can be
> found as DictType.__dict__['__repr__'], but that looks hideous!
> 
> What to do?  Pragmatically, I can make DictType.__repr__ return
> DictType.__dict__['__repr__'], and all will be well in this example.
> But we have to tread carefully here: DictType.__class__ is TypeType,
> but DictType.__dict__['__class__'] is a descriptor for the __class__
> attribute on dictionary objects.
> 
> The best rule I can think of so far is that DictType.__dict__ gives
> the *true* set of attribute descriptors for dictionary objects, and is
> thus similar to Smalltalks's class.methodDict that Jim describes
> below.  DictType.foo is a shortcut that can resolve to either
> DictType.__dict__['foo'] or to an attribute (maybe a method) of
> DictType described in TypeType.__dict__['foo'], whichever is defined.
> If both are defined, I propose the following, clumsy but backwards
> compatible rule: if DictType.__dict__['foo'] describes a method, it
> wins.  Otherwise, TypeType.__dict__['foo'] wins.

I'm not sure I can follow you here: DictType.__repr__ is the
representation method of the dictionary and not inherited
from TypeType, so there should be no problem.

The problem with the misleading error message would only show
up in case DictType does not define a __repr__ method. Then the
inherited one from TypeType would come into play and cause
the problem you mention above.

Thinking in terms of meta-classes, I believe we should implement
this mechanism in the meta-class (TypeType in this case). Its
__getattr__() will have to decide whether or not to expose its
own methods and attributes or not. 

The only catch here is that currently instances and classes have 
control of whether and how to bind found functions as methods or not. 
We should  probably change that to pass complete control over to the 
meta-class object and remove the special control flows currently found
in instance_getattr2() and class_lookup().

In general, I think that meta-classes should not expose their
attributes to the class objects they create, since this causes
way to many problems.

Perhaps I'm oversimplifying things here, but I have a feeling that
we can go a long way by actually trying to see meta-classes as 
first class members in the interpreter design and moving all the 
binding and lookup mechanisms over to this object type. The special 
casing should then take place in the meta-class rather than its 
creations.

-- 
Marc-Andre Lemburg
______________________________________________________________________
Company & Consulting:                           http://www.egenix.com/
Python Software:                        http://www.lemburg.com/python/