If the metaclass of the new class is something more specialized than the
<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
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
procedure, which is called by the default
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
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.
compute-get-n-set method, specialized for classes of
<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
is described in Class Definition Protocol.
compute-get-n-set are called by the
initialize method for classes whose metaclass is
initialize itself can also be modified, by
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.