Next: MOP Specification, Previous: Metaobjects and the Metaobject Protocol, Up: The Metaobject Protocol
It is assumed that the reader is already familiar with standard object orientation concepts such as classes, objects/instances, inheritance/subclassing, generic functions and methods, encapsulation and polymorphism.
This section explains some of the less well known concepts and terminology that GOOPS uses, which are assumed by the following sections of the reference manual.
A metaclass is the class of an object which represents a GOOPS class. Put more succinctly, a metaclass is a class's class.
Most GOOPS classes have the metaclass <class> and, by default,
any new class that is created using define-class has the
metaclass <class>.
But what does this really mean? To find out, let's look in more detail
at what happens when a new class is created using define-class:
(define-class <my-class> (<object>) . slots)
GOOPS actually expands the define-class form to something like
this
(define <my-class> (class (<object>) . slots))
and thence to
(define <my-class>
(make <class> #:supers (list <object>) #:slots slots))
In other words, the value of <my-class> is in fact an instance of
the class <class> with slot values specifying the superclasses
and slot definitions for the class <my-class>. (#:supers
and #:slots are initialization keywords for the dsupers
and dslots slots of the <class> class.)
In order to take advantage of the full power of the GOOPS metaobject
protocol (see MOP Specification), it is sometimes desirable to
create a new class with a metaclass other than the default
<class>. This is done by writing:
(define-class <my-class2> (<object>)
slot ...
#:metaclass <my-metaclass>)
GOOPS expands this to something like:
(define <my-class2>
(make <my-metaclass> #:supers (list <object>) #:slots slots))
In this case, the value of <my-class2> is an instance of the more
specialized class <my-metaclass>. Note that
<my-metaclass> itself must previously have been defined as a
subclass of <class>. For a full discussion of when and how it is
useful to define new metaclasses, see MOP Specification.
Now let's make an instance of <my-class2>:
(define my-object (make <my-class2> ...))
All of the following statements are correct expressions of the
relationships between my-object, <my-class2>,
<my-metaclass> and <class>.
my-object is an instance of the class <my-class2>.
<my-class2> is an instance of the class <my-metaclass>.
<my-metaclass> is an instance of the class <class>.
my-object is <my-class2>.
my-object is <my-metaclass>.
<my-class2> is <my-metaclass>.
<my-class2> is <class>.
<my-metaclass> is <class>.
<my-metaclass> is <class>.
<my-class2> is not a metaclass, since it is does not inherit from
<class>.
<my-metaclass> is a metaclass, since it inherits from
<class>.
The class precedence list of a class is the list of all direct and indirect superclasses of that class, including the class itself.
In the absence of multiple inheritance, the class precedence list is
ordered straightforwardly, beginning with the class itself and ending
with <top>.
For example, given this inheritance hierarchy:
(define-class <invertebrate> (<object>) ...)
(define-class <echinoderm> (<invertebrate>) ...)
(define-class <starfish> (<echinoderm>) ...)
the class precedence list of <starfish> would be
(<starfish> <echinoderm> <invertebrate> <object> <top>)
With multiple inheritance, the algorithm is a little more complicated. A full description is provided by the GOOPS Tutorial: see Class precedence list.
“Class precedence list” is often abbreviated, in documentation and Scheme variable names, to cpl.
An accessor is a generic function with both reference and setter methods.
(define-accessor perimeter)
Reference methods for an accessor are defined in the same way as generic function methods.
(define-method (perimeter (s <square>))
(* 4 (side-length s)))
Setter methods for an accessor are defined by specifying “(setter
<accessor-name>)” as the first parameter of the define-method
call.
(define-method ((setter perimeter) (s <square>) (n <number>))
(set! (side-length s) (/ n 4)))
Once an appropriate setter method has been defined in this way, it can
be invoked using the generalized set! syntax, as in:
(set! (perimeter s1) 18.3)