Metaclasses
\oopindex{metaclasses}
In a class-based approach objects are organized
in taxonomies along the class abstraction.
A class describes the semantics of a set of objects and acts
as a mould from which to create instances.
A class in itself is not an object but a syntactical construct
used to describe objects.
However, a number of class-based languages like Loops,
Smalltalk, CommonLoops and Clos,
allow a class to be characterized in a more abstract way
by means of a metaclass.
Metaclasses, in these languages, are used to implement the
behavior of a class regarded as an object, behavior that is embodied
in class variables and class methods.
In addition, the implementation of a class
by means of a metaclass allows the programmer to inspect
the properties of a class dynamically.
For instance a class may answer to a request
whether it supports a particular method.\ftn{
Static members in C++ do not support
such reflective capabilities,
although library packages exist -- as for example the NIHCL-library [GOP90] --
that do provide such features for C++.
}
\oopindex{modeling}
From the perspective of object oriented modeling,
metaclasses provide the means to capture general properties of the system
on a higher level, by defining the appropriate metaclass for a category of classes.
Three-level architecture
In Smalltalk and Loops, the dichotomy between classes and objects
gives rise to a three-level architecture based on the distinction between
objects, classes and metaclasses.
The inheritance and instantiation structure of this architecture is pictured in the
diagram below.
.so three
The diagram embodies two hierarchies, the hierarchy determined by
the subclass relation (indicated by the solid arrows), and
the hierarchy determined by the instance relation (indicated by the dotted
arrows).
The diagram contains three system-defined entities, namely Object, Class
and MetaClass.
Object is the root of the inheritance hierarchy, since every class (including metaclasses)
must inherit the functionality of Object.
Conversely, every ordinary class is an instance of MetaClass, or a subclass thereof.
Metaclasses, such as Class and the user defined ListMetaClass,
are instances of the system-defined entity MetaClass.
MetaClass has a quite peculiar status in this diagram since (the appropriate
arrow is omitted) it must be regarded as an instance of itself.
The capability of creating instances ultimately comes from MetaClass.
This capability is inherited by both the (system-defined) metaclass
Class and all user defined metaclasses.\ftn{
In Smalltalk, the user is not allowed to define own metaclasses.
In Smalltalk,
to each class corresponds a metaclass
that is hidden from the user.
}
In the diagram, the object level contains a single object b1
that is an instance of the class Book.
Another user defined class is the class Point, which is an instance of Class and a subclass of the class
Object.
The architecture sketched by this diagram has a fixed number of levels, corresponding to
the distinct notions of object, class and metaclass.
The disadvantage of such an architecture from the point of view
of object oriented modeling is that generalizations
with respect to the functionality of the system may be taken only one level up
above the class level.
In principle, one would like to allow an arbitrary number of levels
at which such generalizations are possible.
Reflective architecture
\oopindex{reflection}
\nop{
The architecture sketched above has a fixed number of levels
corresponding to the conceptually distinct notions of object,
class and metaclass.
}
What we need is a view that unifies the notions of
object, class and metaclass in a way that allows
us to define metaclasses to an arbitrary level.
In [Cointe87]
a solution is given that unifies these concepts by taking a class as an
object defined by a real class.
The key to this solution is to provide a reflective definition of a class,
as illustrated in the diagram below.
\begin{center}
.so reflect
\end{center}
This diagram pictures that Object is an instance of Class.
Class, on the other hand, inherits its behavior from Object
but is an instance of itself.
\oopindex{postulates}
The reflective model introduced in [Cointe87] is fully described by
the following postulates:
- An object encapsulates data and procedures.
- Objects are activated by message passing.
A message specifies what procedure to apply by providing
a method selector and the appropriate arguments.
- Every object belongs to a class that specifies the objects
attributes (data) and behavior (methods or procedures).
Objects are created as instances of a class.
- A class is also an object, instantiated by another class,
called its metaclass.
Consequently, to each class is associated a metaclass that
describes its behavior as an object.
- A class can be defined as a subclass of one or many
other class(es).
The subclassing mechanism allows sharing of instance variables and methods,
and is called inheritance.
The class Object represents the most common behavior shared
by all objects.
- Instance variables of an object define a local
environment. Class variables define a global environment shared
by all the instances of a class.
These class variables are defined at the metaclass level.
It must hold that the class variable of an object is
an instance variable of the objects class.
In other words, these postulates require that Object lies
at the root of the inheritance hierarchy
since every class is an object as well, and that Class lies
at the root of the instantiation hierarchy as it provides the
capability of creating new instances.
Having Class at the root of the instantiation hierarchy
entails a circular definition of Class,
since Class must be its own instance.
In order to act as an object,
a class must have an attribute name that records the class name,
an attribute supers that tells from which classes attributes
and methods are inherited, an attribute iv that records the local variables
of the instances of the class, and an attribute methods
that contains the methods defined for objects of the class.
In accordance with this discussion, we may instantiate the (metaclass) Class
by the reflective pattern below.
\yprog{Class}{
name supers iv methods
Class (Object) (name supers iv methods) (new ...)
}
Each class that displays such a reflective pattern may be regarded
as a metaclass,
since its instance variables reflect exactly the properties of a class.
Minimally, a class must support the method new in order to create instances.
In the picture below, this scheme is illustrated
by using Class as a metaclass for a Point class,
that has two points as actual (object) instances.
$=