For each kind of program element there is a corresponding
basic metaobject class
.
These are the classes: CLASS
, CLOS:SLOT-DEFINITION
,
GENERIC-FUNCTION
, METHOD
and METHOD-COMBINATION
.
A metaobject class
is a subclass of exactly one of these classes.
The results are undefined if an attempt is made to define a CLASS
that is a subclass of more than one basic metaobject class.
A metaobject is an instance of a metaobject class.
Each metaobject represents one program element. Associated with
each metaobject is the information required to serve its role. This
includes information that might be provided directly in a user interface
macro such as DEFCLASS
or DEFMETHOD
. It also includes information
computed indirectly from other metaobjects such as that computed from
class inheritance or the full set of methods associated with a generic
function.
Much of the information associated with a metaobject is in the form of connections to other metaobjects. This interconnection means that the role of a metaobject is always based on that of other metaobjects. As an introduction to this interconnected structure, this section presents a partial enumeration of the kinds of information associated with each kind of metaobject. More detailed information is presented later.
A class metaobject determines the structure and the default behavior of its instances. The following information is associated with class metaobjects:
STRING
or NIL
.See also Section 29.3, “Classes”
A slot definition metaobject contains information about the definition of a slot. There are two kinds of slot definition metaobjects:
DEFCLASS
forms.Associated with each class metaobject is a list of direct slot definition metaobjects representing the slots defined directly in the class. Also associated with each class metaobject is a list of effective slot definition metaobjects representing the set of slots accessible in instances of that class.
The following information is associated with both direct and effective slot definitions metaobjects:
DEFCLASS
form.DEFCLASS
form. The
initialization form together with its lexical environment is available
as a function of no arguments which, when called, returns the result
of evaluating the initialization form in its lexical environment. This
is called the initfunction of the slot.
STRING
or NIL
.Certain other information is only associated with direct slot definition metaobjects. This information applies only to the direct definition of the slot in the class (it is not inherited).
DEFCLASS
form are broken down
into their equivalent readers and writers in the direct slot
definition.Information, including inherited information, which applies to the definition of a slot in a particular class in which it is accessible is associated only with effective slot definition metaobjects.
See also Section 29.4, “Slot Definitions”
A generic function metaobject contains information about a generic function over and above the information associated with each of the generic function's methods.
LIST
.
The “declarations” are available as a list of declaration specifiers.
There is a slight misnomer in the naming of functions and options in this document: Where the term “declaration” is used, actually a declaration specifier is meant.
STRING
or NIL
.See also Section 29.5, “Generic Functions”
A method metaobject
contains information about a specific METHOD
.
LIST
of of non-NIL
atoms.LIST
.
FUNCTION
. This
function can be applied to arguments and a list of next methods using
APPLY
or FUNCALL
.STRING
or NIL
.See also Section 29.6, “Methods”
A specializer metaobject
represents the specializers of a METHOD
.
class metaobjects are themselves specializer metaobjects. A special
kind of specializer metaobject is used for EQL
specializers.
See also Section 29.8, “Specializers”
A method combination metaobject represents the information about the method combination being used by a generic function.
This document does not specify the structure of method combination metaobjects.
See also Section 29.9, “Method Combinations”
The inheritance structure of the specified metaobject classes is
shown in Table 29.1, “Direct Superclass Relationships Among The Specified Metaobject Classes”. The class of every class
shown is STANDARD-CLASS
except for the classes T
and FUNCTION
,
which are instances of the class BUILT-IN-CLASS
, and the classes
GENERIC-FUNCTION
and STANDARD-GENERIC-FUNCTION
, which are
instances of the class CLOS:FUNCALLABLE-STANDARD-CLASS
.
Table 29.1. Direct Superclass Relationships Among The Specified Metaobject Classes
Each class with a “yes” in the “Abstract”
column is an abstract class and is not intended to
be instantiated. The results are undefined if an attempt is made to
make an instance of one of these classes with MAKE-INSTANCE
.
Each class with a “yes” in the “Subclassable” column can be used as direct superclass for portable programs. It is not meaningful to subclass a class that has a “no” in this column.
The class METHOD
is also subclassable: It
is possible to create subclasses of METHOD
that do not inherit
from STANDARD-METHOD
.
The class CLOS:FUNCALLABLE-STANDARD-OBJECT
's class
precedence list contains FUNCTION
before STANDARD-OBJECT
, not
after STANDARD-OBJECT
.
This is the most transparent way to realize the [ANSI CL standard] requirement
(see the [ANSI CL standard] section 4.2.2
“Type Relationships”)
that GENERIC-FUNCTION
's class precedence list contains
FUNCTION
before STANDARD-OBJECT
.
The classes STANDARD-CLASS
, CLOS:STANDARD-DIRECT-SLOT-DEFINITION
, CLOS:STANDARD-EFFECTIVE-SLOT-DEFINITION
,
STANDARD-METHOD
, CLOS:STANDARD-READER-METHOD
,
CLOS:STANDARD-WRITER-METHOD
and STANDARD-GENERIC-FUNCTION
are called
standard metaobject
classes.
For each kind of metaobject, this is the class the user interface
macros presented in the CLOS use by default. These are also the
classes on which user specializations are normally based.
The classes BUILT-IN-CLASS
, CLOS:FUNCALLABLE-STANDARD-CLASS
and
CLOS:FORWARD-REFERENCED-CLASS
are special-purpose class metaobject classes.
Built-in classes are instances of the class BUILT-IN-CLASS
.
The class CLOS:FUNCALLABLE-STANDARD-CLASS
provides a special kind of
instances described in Section 29.10.2, “Funcallable Instances”.
When the definition of a class references another class which has not
yet been defined, an instance of CLOS:FORWARD-REFERENCED-CLASS
is used as
a stand-in until the class is actually defined.
CLOS:FORWARD-REFERENCED-CLASS
in CLISPThe class CLOS:FORWARD-REFERENCED-CLASS
is implemented in a way
that fixes several flaws in the [AMOP] specification.
It is not a subclass of CLASS
and CLOS:SPECIALIZER
, just a
subclass of CLOS:METAOBJECT
, because forward references to classes are
not classes and cannot be used as specializers of methods. An [AMOP]
compatibility mode is provided, however, if you set the variable
CUSTOM:*FORWARD-REFERENCED-CLASS-MISDESIGN*
to T
.
In this mode, CLOS:FORWARD-REFERENCED-CLASS
is formally a subclass of
CLASS
and CLOS:SPECIALIZER
, but the behaviour of
CLOS:FORWARD-REFERENCED-CLASS
instances is the same.
The [AMOP] says that the first argument of CLOS:ENSURE-CLASS-USING-CLASS
can
be a CLOS:FORWARD-REFERENCED-CLASS
.
But from the description of CLOS:ENSURE-CLASS
, it is clear that it can
only be a class returned by FIND-CLASS
, and [ANSI CL standard] FIND-CLASS
cannot return a CLOS:FORWARD-REFERENCED-CLASS
.
The [AMOP] says that CLOS:ENSURE-CLASS-USING-CLASS
creates a
CLOS:FORWARD-REFERENCED-CLASS
for not-yet-defined class symbols among the
direct-superclasses list. But this leads to many
CLOS:FORWARD-REFERENCED-CLASS
with the same name (since they cannot be
stored and retrieved through FIND-CLASS
), and since CHANGE-CLASS
preserves the EQ
-ness, after the class is defined, we have many
class objects with the same name.
In the direct-superclasses list of non-finalized classes,
CLOS:FORWARD-REFERENCED-CLASS
instances can occur, denoting classes that
have not yet been defined. When or after such a class gets defined,
the CLOS:FORWARD-REFERENCED-CLASS
instance is replaced with the real
class. CLISP uses simple object replacement, not CHANGE-CLASS
, in
this process.
The class STANDARD-OBJECT
is the default direct
superclass of the class STANDARD-CLASS
. When an instance
of the class STANDARD-CLASS
is created, and no direct superclasses are
explicitly specified, it defaults to the class STANDARD-OBJECT
. In
this way, any behavior associated with the class STANDARD-OBJECT
will be inherited, directly or indirectly, by all instances of the class
STANDARD-CLASS
. A subclass of STANDARD-CLASS
may have a different
class as its default direct superclass, but that class must be a
subclass of the class STANDARD-OBJECT
.
The same is true for CLOS:FUNCALLABLE-STANDARD-CLASS
and
CLOS:FUNCALLABLE-STANDARD-OBJECT
.
The class CLOS:SPECIALIZER
captures only the most basic behavior of
method specializers, and is not itself intended to be instantiated. The
class CLASS
is a direct subclass of CLOS:SPECIALIZER
reflecting the
property that classes by themselves can be used as method specializers.
The class CLOS:EQL-SPECIALIZER
is used for EQL
specializers.
The purpose of the Metaobject Protocol is to provide users with a powerful mechanism for extending and customizing the basic behavior of the CLOS. As an object-oriented description of the basic CLOS behavior, the Metaobject Protocol makes it possible to create these extensions by defining specialized subclasses of existing metaobject classes.
The Metaobject Protocol provides this capability without interfering with the implementor's ability to develop high-performance implementations. This balance between user extensibility and implementor freedom is mediated by placing explicit restrictions on each. Some of these restrictions are general---they apply to the entire class graph and the applicability of all methods. These are presented in this section.
The following additional terminology is used to present these restrictions:
i
is interposed
between two other classes k1
and k2
if and only
if there is some path, following direct superclasses, from the class
k1
to the class k2
which includes i
.x1
... xn
, are
defined in this specification as the classes k1
... kn
, but in
the implementation, one or more of the specializers
xl
, is a superclass of the class
given in the specification kl
.
For a given generic function and set of arguments, a
method k2
extends
a method k1
if and only if:
k1
and
k2
are both associated with the given generic function
k1
and k2
are both applicable to the given
arguments,k2
is executed
before k1
,k1
will be executed if and only if
CALL-NEXT-METHOD
is invoked from within the body of k2
and
CALL-NEXT-METHOD
is invoked from within the body
of k2
, thereby causing k1
to be executed.
For a given generic function and set of arguments, a
method k2
overrides
a method k1
if and only if conditions i
through iv above hold and,
instead of v,
CALL-NEXT-METHOD
is not invoked from within the
body of k2
, thereby preventing k1
from being executed.
Portable programs are allowed to define subclasses of specified classes, and are permitted to define methods on specified generic functions, with the following restrictions:
EQL
specializer whose associated value is an instance of a specified
class.CALL-NEXT-METHOD
.Portable programs may define methods that override specified methods only when the description of the specified method explicitly allows this. Typically, when a method is allowed to be overridden, a small number of related methods will need to be overridden as well.
An example of this is the specified methods on the generic
functions CLOS:ADD-DEPENDENT
, CLOS:REMOVE-DEPENDENT
and CLOS:MAP-DEPENDENTS
.
Overriding a specified method on one of these generic functions requires
that the corresponding method on the other two generic functions be
overridden as well.
Portable methods on specified generic functions
specialized to portable metaobject classes must be defined before any
instances of those classes (or any subclasses) are created, either
directly or indirectly by a call to MAKE-INSTANCE
. Methods can be
defined after instances are created by ALLOCATE-INSTANCE
however.
Portable metaobject classes cannot be redefined.
The purpose of this last restriction is to permit implementations to provide performance optimizations by analyzing, at the time the first instance of a metaobject class is initialized, what portable methods will be applicable to it. This can make it possible to optimize calls to those specified generic functions which would have no applicable portable methods.
When a metaobject class is redefined,
CLISP issues a WARNING
that the redefinition has no effect.
To avoid this warning, place all metaobject class definitions in a
separate file, compile it in a separate session
(because DEFCLASS
in CLISP is evaluated at compile time too;
see Section 29.2.3.2, “Compile-file Processing of Specific User Interface Macros”),
and then LOAD
it only once per session.
The results are undefined if any of these restrictions are violated.
The specification technology used in this document needs further development. The concepts of object-oriented protocols and subclass specialization are intuitively familiar to programmers of object-oriented systems; the protocols presented here fit quite naturally into this framework. Nonetheless, in preparing this document, we have found it difficult to give specification-quality descriptions of the protocols in a way that makes it clear what extensions users can and cannot write. Object-oriented protocol specification is inherently about specifying leeway, and this seems difficult using current technology.
Implementations are allowed latitude to modify the structure of specified classes and methods. This includes: the interposition of implementation-specific classes; the promotion of specified methods; and the consolidation of two or more specified methods into a single method specialized to interposed classes.
Any such modifications are permitted only so long as for any
portable class k
that is a subclass of one or more specified classes
k1
... kn
, the following conditions are met:
k
, the
classes k1
... kn
must appear in the same order as they would
have if no implementation-specific modifications had been made.
k
may inherit, by virtue of
being a direct or indirect subclass of a specified class, any slot for
which the name is a symbol accessible in the “COMMON-LISP-USER” package or
exported by any package defined in the [ANSI CL standard].A list in which the first element is one of the symbols
DEFCLASS
, DEFMETHOD
, DEFGENERIC
, DEFINE-METHOD-COMBINATION
,
CLOS:GENERIC-FUNCTION
, CLOS:GENERIC-FLET
or CLOS:GENERIC-LABELS
, and which has proper
syntax for that macro is called a user interface macro
form. This document provides an extended specification of
the DEFCLASS
, DEFMETHOD
and DEFGENERIC
macros.
The user interface macros DEFCLASS
, DEFGENERIC
and DEFMETHOD
can be used not only to define metaobjects that are instances of the
corresponding standard metaobject class, but also to define metaobjects
that are instances of appropriate portable metaobject classes. To make
it possible for portable metaobject classes to properly process the
information appearing in the macro form, this document provides a
limited specification of the processing of these macro forms.
User interface macro forms can be evaluated or compiled and later executed. The effect of evaluating or executing a user interface macro form is specified in terms of calls to specified functions and generic functions which provide the actual behavior of the macro. The arguments received by these functions and generic functions are derived in a specified way from the macro form.
Converting a user interface macro form into the arguments to the appropriate functions and generic functions has two major aspects: the conversion of the macro argument syntax into a form more suitable for later processing, and the processing of macro arguments which are forms to be evaluated (including method bodies).
In the syntax of the DEFCLASS
macro, the initform
and default-initarg-initial-value-form
arguments are forms which will be evaluated one or more times after the
macro form is evaluated or executed. Special processing must be done on
these arguments to ensure that the lexical scope of the forms is
captured properly. This is done by building a function of zero
arguments which, when called, returns the result of evaluating the form
in the proper lexical environment.
In the syntax of the DEFMETHOD
macro
the forms
argument is a list of forms that
comprise the body of the method definition. This list of forms must be
processed specially to capture the lexical scope of the macro form. In
addition, the lexical functions available only in the body of methods
must be introduced. To allow this and any other special processing
(such as slot access optimization), a specializable protocol is used for
processing the body of methods.
This is discussed in Section 29.6.3.1.1, “Processing Method Bodies”.
It is a common practice for Common Lisp compilers, while processing a file
or set of files, to maintain information about the definitions that have
been compiled so far. Among other things, this makes it possible to
ensure that a global macro definition (DEFMACRO
form) which appears in
a file will affect uses of the macro later in that file.
This information about the state of the compilation is called the
COMPILE-FILE
environment.
When compiling files containing CLOS definitions, it is useful
to maintain certain additional information in the COMPILE-FILE
environment.
This can make it possible to issue various kinds of warnings (e.g.,
lambda list congruence) and to do various performance optimizations that
would not otherwise be possible.
At this time, there is such significant variance in the way
existing Common Lisp implementations handle COMPILE-FILE
environments that it
would be premature to specify this mechanism. Consequently, this
document specifies only the behavior of evaluating or executing user
interface macro forms. What functions and generic functions are called
during COMPILE-FILE
processing of a user interface macro form is not
specified. Implementations are free to define and document their own
behavior. Users may need to check implementation-specific behavior
before attempting to compile certain portable programs.
DEFCLASS
Section 29.3.1, “Macro DEFCLASS
”
CLISP evaluates DEFCLASS
forms also at
compile time.
DEFMETHOD
Section 29.6.3.1, “Macro DEFMETHOD
”
CLISP does not evaluate DEFMETHOD
forms at compile time except as necessary for signature checking.
DEFGENERIC
Section 29.5.3.1, “Macro DEFGENERIC
”
CLISP does not evaluate DEFGENERIC
forms at compile time except as necessary for signature checking.
Like other objects, metaobjects can be created by calling
MAKE-INSTANCE
. The initialization arguments passed to MAKE-INSTANCE
are used to initialize the metaobject in the usual way. The set of
legal initialization arguments, and their interpretation, depends on the
kind of metaobject being created. Implementations and portable programs
are free to extend the set of legal initialization arguments. Detailed
information about the initialization of each kind of metaobject are
provided in the appropriate sections:
These notes document CLISP version 2.49.93+ | Last modified: 2018-02-19 |