Re: mjc4y@brunelleschi.cs.virginia.edu: python object model

Guido.van.Rossum@cwi.nl
Wed, 24 Aug 1994 15:25:59 +0200

Here's a follow-up I received on the python object model. I hope
further discussion can be don in this wider forum! (Rob: I
hope you don't mind me forwarding this to the list too...)

--Guido van Rossum, CWI, Amsterdam <Guido.van.Rossum@cwi.nl>
<URL:http://www.cwi.nl/cwi/people/Guido.van.Rossum.html>

------- Forwarded Message

Date: Tue, 23 Aug 1994 17:06:10 -0700
From: deline@src.dec.com
To: conway@server.cs.Virginia.EDU
cc: tnb2d@server.cs.Virginia.EDU, guido@cwi.nl
Subject: Re: python object model

Matt,

On the whole, I liked your presentation of metaclasses for Python,
but you actually made it a bit trickier than it needs to be. Here's
my take on how you'd implement a metaobject protocol for Python.

First, some important observations (and vocabulary groundwork):

an object is an instance of a class
a class is an instance of a metaclass
but a metaclass is just a class

(This last one can be worded as, "a metaclass is a class that just
so happens to implement the behavior of what a class does.") Don't
let the metacircularity ("recursion") of these statements bother
you -- we'll get to that.

[Quick aside on notation: To try to minimize confusion, I'll Capitalize
the names of classes, lowercase the names of instances, and put the
names of metaclasses in ALL_CAPS.]

So here's how a metaobject protocol would change (and simplify!)
the current Python implementation. The first implication is that
there no longer needs to be separate types for objects (class instances)
and classes (i.e. instanceobject and classobject). They get folded
into a single type, let's call it instanceobject. Next we create
an instanceobject "by hand" and bind it to a global Python identifier,
call it "CLASS". This is the one built-in metaclass. Its methods
implement the functionality currently associated with the code in
classobject.c. By "hand crafting" this one metaclass in C, the metacircularity

is broken -- the C code is the "base case" for the recursive definition,
so to speak.

Given this, a Python programmer could create new metaclasses by subclassing,
as follows. To borrow Matt's example,

class SMART_CLASS(CLASS):
def __callmethod__(self, meth, *args):
print "calling method", meth, "with", args
# really call the method
apply(meth, self + args)

Notice that no special syntax or anything is needed. The definition
above really is just a plain-old ordinary Python class definition.

There's only one place the syntax would need to be changed and that
is to indicate that a class is an instance of a particular metaclass.
Again, to borrow Matt's example:

class SmartRect is SMART_CLASS:
def __init__(self, color):
self.color = color

def getcolor(self):
return self.color

Omitting the "is" clause is equivalent to "is CLASS".

*** N.B. With a metaobject protocol in place, the syntax above is
just syntactic sugar for method calls on the metaclass. For example,
you could imagine the class definition above being sugar for:

SmartRect = SMART_CLASS().init()
SmartRect.addMethod(__init__, <parsed version of __init__>)
SmartRect.addMethod(getcolor, <parsed version of getcolor>)

where <parsed version of xxxx> is just my way of saying that the
second argument is the methodobject that the parser creates when
parsing the class definition of xxxx. Also note that the code above
is meant to be evocative of a metaobject protocol in general and
shouldn't be taken as a suggestion for a final MOP for Python. Designing
a good MOP is hard work. Finally, it would cause an obvious metacircularity
problem is the definitions of metaclasses (like the one for SMART_CLASS
above) were allowed to have an "is" clause. A metaclass is by definition
an instance of CLASS, so the "is" clause is forbidden in the definition
of a metaclass. (To be really fussy, the definition of a metaclass
is any class definition where at least one of the classes in the
superclass list is a subclass of CLASS. Read *that* ten times fast!)

One last important thing to notice (especially for Guido) is that
adding a metaobject protocol to Python is completely backward compatible
with current versions of Python. Everything that changes is inside
the implementation, except for the "is" clause, and classes that omit the
"is" clause would have exactly the same meaning that they do with
the current version of Python.

Matt asks why you would want to have a metaobject protocol. Unsurprisingly,
this question has the same answer as the question, "In an OOP language,
why would you want to create a subclass of a class?"

* to change its implementation (by adding data items)
* to change its behavior in a compatible way (by overriding methods)
* to suppliment its behavior (by adding methods)

The power of a metaobject protocol is the power to create subclasses
of CLASS. For example, all of Steve Miale's thesis work could have
been done in Python had there been a Python MOP. Basically any of
your favorite features from other OOP language could be implemented
for Python using the MOP, e.g. changing inheritance on the fly,
public/protected/private clauses, persistant objects, objects that
migrate transparently over the network. Chances are, whatever the
OOP semantics a Python programmer wants, she could implement it for
herself using the MOP.

Rob

P.S. There's one implementation issue I skipped to keep things simple.
It has to do with the following. If you have definitions like this

class A_CLASS(CLASS): ... etc ...
class B_CLASS(CLASS): ... etc ...

class Fred is A_CLASS: ... etc ...
class Barney is B_CLASS: ... etc ...

class Ethel(Fred, Barney): ... etc ...

The question is: what metaclass is Ethel an instance of? It's easy
to deal with this, but this mail is long enough as is. We can chat
about it if you want in further mail.

------- End of Forwarded Message