Node:Customizing Class Definition, Next:STKlos Compatibility, Previous:Class Definition Internals, Up:Defining New Classes
During the initialization of a new class, GOOPS calls a number of generic functions with the newly allocated class instance as the first argument. Specifically, GOOPS calls the generic function
where class is the newly allocated class instance, and the default
initialize
method for arguments of type <class>
calls the
generic functions
compute-slots
compute-slots
that includes a
#:getter
or #:accessor
slot option
compute-slots
that includes a
#:setter
or #:accessor
slot option.
If the metaclass of the new class is something more specialized than the
default <class>
, then the type of class in the calls above
is more specialized than <class>
, and hence it becomes possible
to define generic function methods, specialized for the new class's
metaclass, that can modify or override the default behaviour of
initialize
, compute-cpl
or compute-get-n-set
.
compute-cpl
computes the class precedence list ("CPL") for the
new class (see Class precedence list), and returns it as a list of
class objects. The CPL is important because it defines a superclass
ordering that is used, when a generic function is invoked upon an
instance of the class, to decide which of the available generic function
methods is the most specific. Hence compute-cpl
could be
customized in order to modify the CPL ordering algorithm for all classes
with a special metaclass.
The default CPL algorithm is encapsulated by the compute-std-cpl
procedure, which is in turn called by the default compute-cpl
method.
compute-std-cpl class | procedure |
Compute and return the class precedence list for class according to the algorithm described in Class precedence list. |
compute-slots
computes and returns a list of all slot definitions
for the new class. By default, this list includes the direct slot
definitions from the define-class
form, plus the slot definitions
that are inherited from the new class's superclasses. The default
compute-slots
method uses the CPL computed by compute-cpl
to calculate this union of slot definitions, with the rule that slots
inherited from superclasses are shadowed by direct slots with the same
name. One possible reason for customizing compute-slots
would be
to implement an alternative resolution strategy for slot name conflicts.
compute-get-n-set
computes the low-level closures that will be
used to get and set the value of a particular slot, and returns them in
a list with two elements.
The closures returned depend on how storage for that slot is allocated.
The standard compute-get-n-set
method, specialized for classes of
type <class>
, handles the standard GOOPS values for the
#:allocation
slot option (see allocation). By
defining a new compute-get-n-set
method for a more specialized
metaclass, it is possible to support new types of slot allocation.
Suppose you wanted to create a large number of instances of some class
with a slot that should be shared between some but not all instances of
that class - say every 10 instances should share the same slot storage.
The following example shows how to implement and use a new type of slot
allocation to do this.
(define-class <batched-allocation-metaclass> (<class>)) (let ((batch-allocation-count 0) (batch-get-n-set #f)) (define-method (compute-get-n-set (class <batched-allocation-metaclass>) s) (case (slot-definition-allocation s) ((#:batched) ;; If we've already used the same slot storage for 10 instances, ;; reset variables. (if (= batch-allocation-count 10) (begin (set! batch-allocation-count 0) (set! batch-get-n-set #f))) ;; If we don't have a current pair of get and set closures, ;; create one. make-closure-variable returns a pair of closures ;; around a single Scheme variable - see goops.scm for details. (or batch-get-n-set (set! batch-get-n-set (make-closure-variable))) ;; Increment the batch allocation count. (set! batch-allocation-count (+ batch-allocation-count 1)) batch-get-n-set) ;; Call next-method to handle standard allocation types. (else (next-method))))) (define-class <class-using-batched-slot> () ... (c #:allocation #:batched) ... #:metaclass <batched-allocation-metaclass>)
The usage of compute-getter-method
and compute-setter-method
is described in MOP Specification.
compute-cpl
and compute-get-n-set
are called by the
standard initialize
method for classes whose metaclass is
<class>
. But initialize
itself can also be modified, by
defining an initialize
method specialized to the new class's
metaclass. Such a method could complete override the standard
behaviour, by not calling (next-method)
at all, but more
typically it would perform additional class initialization steps before
and/or after calling (next-method)
for the standard behaviour.