[Types-sig] Q: What are Meta-classes anyhoo?

Evan Simpson evan@tokenexchange.com
Fri, 4 Dec 1998 10:27:18 -0600

>Further on, it goes on to say,
>"Whenever a new class is created, a new metaclass is created for it
>automatically.  Metaclasses are similar to other classes because they
>contain methods used by their instances.  Metaclasses are different
>from other classes because they themselves are not instances of
>metaclasses.  Instead, they are all instances of a class called
>So, like Evan's #6, metaclasses contain class methods.  In actuality,
>in Smalltalk, constuctors are just class methods, ie, methods of
>class's metaclass.

Eeek.  I like the part about class methods, but the business of
automatically generating a new metaclass behind the scenes for every new
class is a bit odd.  If all metaclasses are instances of Metaclass, and you
can subclass Metaclass (say with MyMetaClass), how do you get an instance of
MyMetaClass to be the metaclass of a new class? Or does Smalltalk let you
implicitly define your metaclass in the class definition somehow?

>I think with a little bit of thought you could extend it to define/change
>an instances attributes are looked up, etc, etc.  I think it could be
>extended to all kinds of fancy things.

Now that I think about it, if we have static class methods, and they are not
only bound to the class but to the instance on which they are called as an
argument (None if called on the class), then we could specify that the
various hooks (__getattr__, etc.) must be called *before* the instance dict
is examined if the hook is a static class method.  Then we could have:

... defining metaclass MC...
  def __getattr__(klass, inst, attr):
    if inst is not None:
      # fake up the attribute for the instance inst
      # fake up the attribute for the class klass
  def astatic(klass, inst, anarg):
    # similar

... later ...
C = MC()
c = C()
# C.x ALWAYS evaluates as MC.__getattr__(C, None, 'x')
# c.x ALWAYS evaluates as MC.__getattr__(C, c, 'x')
# C.astatic(None, 'foo') is MC.astatic(C, None, 'foo')
# C.astatic(c, 'foo') and c.astatic('foo') are MC.astatic(C, c, 'foo')

Of course, this would mean that we would either have to extend the notation
naturally for (meta){2,}classes, or be unable to access more than two
instanciations down.  Also, the interpreter would be forever having to walk
the meta-chain before doing the simplest operations.  Grrr.  Let's put
static class methods into the dictionary of everything they're bound to, and
to heck with dynamic behavior; What sane person wants to mess with an
object's (meta){1,}class at rutime anyway? <0.5 wink>.