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

25381-geller (asg@xyzzy.gamekeeper.bellcore.com)
30 Aug 1994 23:25:37 GMT

In article <Cv22v7.7Ks@rahul.net> Craig Lawson <claw@rahul.net> writes:

Metaclasses! This is great! OK, here are some issues:

First off, I'm a Python newbie, but I'm familiar with metaclasses from
CLOS (where else?). For anyone who is completely baffled by what a
metaclass is, and why anyone would care, a metaclass is just a class
whose instances are class objects. Clear as mud, I know.

Check out The Art of the Metaobject Protocol, by Kiczales, des
Rivieres, and Bobrow (MIT Press, 1991), or significant sections of
Object-Oriented Programming / The CLOS Perspective, by Paepcke (MIT
Press, 1993), for a description and discussion of the CLOS meta-object
protocol (MOP).

1. How can these metaclasses actually help me implement the smart
dictionary given as an example? I mean, beyond just intercepting the
__getslot__ and __setslot__ meta-methods (meta-methods?). How can I
get this Bold-New-Python to parse "{'one':1, 'two':2}" and create a
smart dictionary instead of the standard not-so-smart dictionary?
(Display is easy: we already have __str__ and __repr__).
I'm talking about extending the syntax, and so extending the parser.
Can this be done through a metaclass specification? (This question is
starting to sound like a request for C++ operator overloading
features.) The issue here is: how to maintain readability. One of
Python's strengths is it's brevity, and to give that up in favor of
a more universal (and flexible) syntax will cause the language to look
more like Lisp or Scheme.

In CLOS, there's no way to do this -- the parser (reader, in Lisp-ese)
always reads a list as a list, a string as a string, etc. There's no
way to say, "All lists should now be 'super-nifty-lists', instead".

{ A minor note regarding CLOS -- first off, you can't inherit from
built-in classes like list or string, so this can't really be done
anyway; and the Lisp reader is actually completely programmable, so
you actually COULD get it to read (1 2 3) and produce a
super-nifty-list instead of a plain old list, if that was what you
wanted; but not easily. }

2. From the example/proposed metaclass syntax:
metaclass SmartClass:
def __init__(self): ...
It occurs to me that metaclasses can also be inherited, like so:
metaclass SmartClass(StandardClass):
def __init__(self): ...
So we get all the advantages of inheritance when defining metaclasses.

Yes, of course; a metaclass is a class like any other, and so there's
an inheritance hierarchy of metaclasses. Note also that there's a
class Metaclass, of which metaclasses are instances...

3. Inheritance and metaclass conflicts. The example/proposed new
class syntax is:
class SmartRect is SmartClass:
def ...
What would the restrictions be when classes are inherited? Can I do
this:
class SmartRect is SmartClass:
def ...
class SmartPoly(SmartRect) is DumbClass:
def ...
I can imagine arguments both for and against. I haven't worked with
metaclasses, so I'm asking out of ignorance. And, of course, to stir
up the hornet's nest.

In CLOS, unless DumbClass inherited from SmartClass, I don't think
this is allowed. This makes sense to me, but I don't know if it's
absolutely required, or if it could be relaxed.

4. Readability vs. Metaclass Proliferation: Will the ability to monkey
with class operation lead to less readable Python code? I mention
readability again because it is one of Python's strengths, and there
are plenty of languages that are less so. Imagine:
dict1['key'] = 1
dict2['key'] = 1
where "dict1" and "dict2" are of different classes and metaclasses.
They (hopefully) will do something similar, but may cause different
side effects. Is this desirable? Is this behavior similar to one of
C++'s good features, or one of it's bad features?
In the US, if I may delve into a figurative argument, we have a
saying: "Guns don't kill people, people kill people." Which is to say
that programmers should be responsible for their own confusion.
Although, a variation is "Guns don't kill people, bullets kill
people," which is an obfuscated way of saying "Tough shit", except
that people make bullets, so whose responsibile for that? Then
there's "Slogans don't confuse issues, people confuse issues..."

It is always true that providing more power also provides more
opportunities for shooting yourself in the foot. While this doesn't
mean that you should restrict the capabilities of a language, it might
mean that you shouldn't make it trivial to use facilities that make it
easy to shoot yourself (keep guns legal, but make the licensing
requirements strict, and require a waiting period before you can get
one).

For example, in CLOS, there's actually a lot of mucking around with
various peculiar methods that you have to do to make your metaclass
work at all, most of which is highly unobvious. This is usually
considered a flaw, but maybe it's really a feature?

5. How metaclasses will help me: one of my peeves about (some)
object-oriented languages is the unnecessary distinction between
instance variable and method. Why must I write:
instance.calculated_value()
to cause some calculated value to be actually calculated from other
instance variables? It's a value! It may already *be* calculated!
What does the caller care how or when it comes into being? I would
prefer to leave the parentheses off, and leave the implementation,
whether it be dictionary look-up or method call, to the class
implementation. (This can be accomplished with something similar to
the notify-on-change functionality discussed in this thread.)
Well, that's what my code will look like in the future. Do you want
to read it?
How to differentiate between calling the method and returning the
method as a first-class object? Use "instance.calculated_value.im_func"

Yes, you could do this with a metaclass. Other nifty uses: generalized
persistent objects; specialized implementations for performance
optimization; classes that automatically track (keep a list of) their
instances; and classes that automatically provide a trace of all
accesses.

5. Metaclasses: do we need this? It makes the language more complex.
I was reading the Dylan language spec yesterday, and one of the design
goals specified was, "Make the language as simple as possible, and no
simpler." Well, I don't think they've accomplished that, and I can
use Python as an example of how things *could* be simpler. Should this
potentially trite phrase be part of Python's design goal?

The issue is whether the additional power and flexibility is worth the
additional costs in performance, maintainability, and learn-ability
(?). I'm comfortable with the idea of a MOP, so I kind of like the
idea; on the other hand, I can easily see where this could be a source
of confusion to novice users, and my primary attraction to Python is
as an extension language that people who are not experienced
programmers can use. So I'm stuck in the middle, myself.

--
----------------------------------------------------------------------------- 
 Alan Geller                                            phone: (908)699-8285 
 Bell Communications Research                             fax: (908)336-2953 
 444 Hoes Lane                                   e-mail: asg@cc.bellcore.com 
 RRC 5G-110
 Piscataway, NJ 08855-1342