Another weakness of the classical object model
(or perhaps one of its strengths)
is that the concept of a class easily
lends itself to being overloaded with additional
meanings and features such as class variables
and metaclasses.
These notions lead to extensions to
the original class/instance scheme
that are hard to unify in a single elegant
framework.
In this section
we will study a proposal based on a reflexive
relation between classes and objects.
Dependent on one's perspective, a class may either
be regarded as a kind of abstract data type
(specifying the operational interface of its object instances)
or, more pragmatically, as a template for object creation
(that is a means to generate new instances).
The class concept
- abstract data type -- interface description
- object generator -- template for creation
- repository -- for sharing resources
- object -- instance of a metaclass
slide: The concept of class
In addition, however, in a number of systems
a class may be used as a repository for sharing
class-wide resources.
For example, the Smalltalk language allows the definition of
class variables that are accessible to all instances of the class.
See slide [5-class].
Class variables
Clearly, the use of class variables
violates what we have called the distribution boundary
in section [multi-paradigm],
since it allows objects to reach out of their
encapsulation borders.
Class variables may also be employed in C++
by defining data members as static.
Apart from class variables, Smalltalk also supports
the notion of class methods,
which may be regarded as routines having the class
and its instances as their scope.
Class methods in Smalltalk are typically used
for the creation and initialization of new instances of the class
for which they are defined.
In C++, creation and initialization is taken care
of by the constructor(s) of a class,
together with the (system supplied) new
operator.
Class methods, in C++, take the form
of static member functions that are like
ordinary functions
(apart from their restricted scope and their calling syntax,
which is of the form ).
Contrary to classes in C++,
classes in Smalltalk have a functionality
similar to that of objects.
Classes in Smalltalk provide
encapsulation (encompassing class variables and
class methods) and message passing
(for example for the creation and initialization
of new instances).
To account for this object-like behavior,
the designers of Smalltalk have introduced the notion
of metaclass of which a class is an instance.
Metaclasses
In the classical object model, two relations
play a role when describing the
architectural properties of a system.
The first relation is the instance relation
to indicate that an object O is an instance of a class
C.
The second (equally important) relation is
the inheritance relation,
which indicates that a class C is a subclass
(or derived from) a given (ancestor) class P.
See slide [5-diagram].
Classes
slide: The {\em instance} and {\em inheritance} relation
When adopting the philosophy
everything is an object
together with the idea that
each object is an instance of a class
(as the developers of Smalltalk did),
we evidently get into problems when we try to explain
the nature (and existence) of a class.
To be an object, a class itself must be an instance
of a class (which for convenience we will call
a metaclass).
Take, for example, the class Point.
This class must be an instance of a (meta)class
(say Class) which in its turn must be an instance of a (meta)
class (say MetaClass),
and so on.
Clearly, following the instance relation
leads to an infinite regress.
hence, we must postulate some
system-defined MetaClass (at a certain level)
from which to instantiate the (metaclasses of)
actual classes such as Point.
See slide [5-architecture].
Meta architecture
}{}
- \mbox{}\hspace{0cm} \parbox{8cm}{
\begin{mfpic}[30][20]{0}{10}{0}{10}
\label[cc]{5}{9}{MetaClass}
\label[cc]{3}{5}{Class}
\label[cc]{8}{5}{ListMetaClass}
\label[cc]{1}{1}{Point}
\label[cc]{5}{1}{Object}
\label[cc]{9}{1}{Book}
\arrow{(4.9,8.5),(2.9,5.5)}
\dottedarrow{(3.2,5.5),(5.2,8.5)}
\dottedarrow{(8.0,5.5),(5.2,8.5)}
\dottedarrow{(1,1.5),(2.5,4.5)}
\dottedarrow{(9,1.5),(8.2,4.5)}
\arrow{(2.9,4.5),(4.9,1.5)}
\dottedarrow{(5.2,1.5),(3.2,4.5)}
\arrow{(2,1),(4,1)}
\arrow{(8,1),(6,1)}
\arrow{(6.3,5),(4,5)}
\end{mfpic}
}
}{
- \mbox{}\hspace{0cm} \parbox{8cm}{
\begin{mfpic}[20][10]{0}{10}{0}{10}
\label[cc]{5}{9}{MetaClass}
\label[cc]{3}{5}{Class}
\label[cc]{8}{5}{ListMetaClass}
\label[cc]{1}{1}{Point}
\label[cc]{5}{1}{Object}
\label[cc]{9}{1}{Book}
\arrow{(4.9,8.5),(2.9,5.5)}
\dottedarrow{(3.2,5.5),(5.2,8.5)}
\dottedarrow{(8.0,5.5),(5.2,8.5)}
\dottedarrow{(1,1.5),(2.5,4.5)}
\dottedarrow{(9,1.5),(8.2,4.5)}
\arrow{(2.9,4.5),(4.9,1.5)}
\dottedarrow{(5.2,1.5),(3.2,4.5)}
\arrow{(2,1),(4,1)}
\arrow{(8,1),(6,1)}
\arrow{(6.3,5),(4,5)}
\end{mfpic}
}
}
slide: Meta architecture
The figure above is a (more or less) accurate rendering of
the solution provided by Smalltalk.
We may add additional flexibility by
allowing user-defined metaclasses
that may refine the behavior of the system-defined metaclass
Class.
(This is the solution chosen for Loops, see [LOOPS].)
Thus far we have traced the instance relation which leads
(following the reversed arrows)
from top to bottom, from metaclasses to actual
object instances.
As pictured in the diagram above,
the inheritance relation
(followed in the same manner)
goes in exactly the opposite direction,
having the class Object
at the root of the inheritance hierarchy.
For example, the class Point
(while being an instance of the metaclass Class)
is derived by inheritance from the class Object.
Similarly, the (meta)class Class itself inherits
from the class Object, and in its turn the system-defined
metaclass MetaClass inherits from Class.
As for the user-defined metaclasses,
these may be thought of as inheriting
from the system-defined metaclass Class.
Apart from being slightly confusing,
the architecture presented above is rather
inelegant due to the magic
(that is system-defined) number of meta levels.
In the following, we will study a means
to overcome this inelegancy.
Reflection
[Cointe87] proposes an architecture
that unifies the notions of object, class and metaclass,
while allowing metaclasses to be defined at an arbitrary level.
The key to this solution lies in the postulates
characterizing the behavior
of an object-oriented system
given in slide [5-postulates].
Postulates
-- class-based languages
- everything is an object
- every object belongs to a class
- every class inherits from the class Object
- class variables of an object are instance variables
of its class
slide: Class-based languages -- postulates
The first three postulates are quite straightforward.
They agree with the assumptions underlying Smalltalk.
The last postulate, however, stating that a class
variable of an object must be an instance variable
of the objects class (taken as an object),
imposes a constraint of a self-recurrent
or reflexive nature.
This recurrence is pictured in the diagram
below, which displays the object Class as an instance of
itself (that is the class Class).
See slide [5-Class].
In other respects, the diagram is similar to
the diagram depicting the (meta) architecture of Smalltalk
and Loops.
Reflective architecture
}{}
- \mbox{}\hspace{1cm} \parbox{5cm}{
\begin{mfpic}[30][20]{0}{10}{1}{8}
\label[cc]{6}{6}{Class}
\label[cc]{3}{2}{Object}
\arrow{(5.3,5.5),(3.3,2.5)}
\dottedarrow{(3.7,2.5),(5.7,5.5)}
\point{(5.0,5.5)}
\point{(4.2,5.6)}
\point{(4,6)}
\point{(4.2,6.4)}
\curvedarrow{(5.0,5.5),(4,6),(5.0,6.5)}
\end{mfpic}
}
}{
- \mbox{}\hspace{2cm} \parbox{5cm}{
\begin{mfpic}[10][10]{0}{10}{1}{8}
\label[cc]{6}{6}{Class}
\label[cc]{3}{2}{Object}
\arrow{(5.3,5.5),(3.3,2.5)}
\dottedarrow{(3.7,2.5),(5.7,5.5)}
\point{(5.0,5.5)}
\point{(4.2,5.6)}
\point{(4,6)}
\point{(4.2,6.4)}
\curvedarrow{(5.0,5.5),(4,6),(5.0,6.5)}
\end{mfpic}
}
}
slide: Reflective architecture
To indicate how such a reflective relation may be implemented,
[Cointe87] introduces a representation
of objects involving the attributes
name (to indicate the class of the object),
supers (to indicate its ancestor(s)),
iv (to list the instance variables of the object)
and methods (to store the methods belonging
to the object).
In this scheme of representation,
the system-defined metaclass Class
is precisely the object reflecting its own structure
in the values of its attributes, as depicted above.
Every instance of Class may assign values
to its instance variables (contained in iv)
that are appropriate to the instances
that will be created from it.
In general, a metaclass is an object
having at least the attributes of Class
(and possibly more).
See slide [5-reflex-class].
[D
name Class
supers (Object)
iv (name supers iv methods)
methods (new ...)
D]
slide: A reflective definition of {\em Class}
Using this scheme,
an arbitrary towering of metaclasses may
be placed on top of concrete classes,
thus allowing the software developer
to squeeze out the last bit of differential
programming.
Elegant indeed, although it is
doubtful whether many programmers
will endeavor upon such a route.
A nice example of employing (customized)
metaclasses, however, is given in [Malenfant89],
where metaclasses are used to define
the functionality of distribution
and communication primitives employed
by concrete classes.