29.6. Methods
Prev | Chapter 29. Meta-Object Protocol | Next

## 29.6. Methods

### 29.6.1. Inheritance Structure of method metaobject Classes

Figure 29.5. Inheritance structure of method metaobject classes

### 29.6.2. Introspection: Readers for method metaobjects

The reader generic functions which simply return information associated with method metaobjects are presented together here in the format described in Section 29.3.3, “Introspection: Readers for class metaobjects”.

Each of these reader generic functions have the same syntax, accepting one required argument called `method`, which must be a method metaobject; otherwise, an `ERROR` is `SIGNAL`ed. An `ERROR` is also `SIGNAL`ed if the method metaobject has not been initialized.

These generic functions can be called by the user or the implementation.

For any of these generic functions which returns a list, such lists will not be mutated by the implementation. The results are undefined if a portable program allows such a list to be mutated.

#### 29.6.2.1. Generic Function `CLOS:METHOD-SPECIALIZERS`

##### `(`CLOS:METHOD-SPECIALIZERS` `method`)`

Returns a list of the specializers of `method`. This value is a list of specializer metaobjects. This is the value of the `:SPECIALIZERS` initialization argument that was associated with the method during initialization.

#### 29.6.2.2. Generic Function `METHOD-QUALIFIERS`

##### `(`METHOD-QUALIFIERS` `method`)`

Returns a (possibly empty) list of the qualifiers of `method`. This value is a list of non-`NIL` atoms. This is the defaulted value of the `:QUALIFIERS` initialization argument that was associated with the method during initialization.

#### 29.6.2.3. Generic Function `CLOS:METHOD-LAMBDA-LIST`

##### `(`CLOS:METHOD-LAMBDA-LIST` `method`)`

Returns the (unspecialized) lambda list of `method`. This value is a Common Lisp lambda list. This is the value of the `:LAMBDA-LIST` initialization argument that was associated with the method during initialization.

#### 29.6.2.4. Generic Function `CLOS:METHOD-GENERIC-FUNCTION`

##### `(`CLOS:METHOD-GENERIC-FUNCTION` `method`)`

Returns the generic function that `method` is currently connected to, or `NIL` if it is not currently connected to any generic function. This value is either a generic function metaobject or `NIL`. When a method is first created it is not connected to any generic function. This connection is maintained by the generic functions `ADD-METHOD` and `REMOVE-METHOD`.

#### 29.6.2.5. Generic Function `CLOS:METHOD-FUNCTION`

##### `(`CLOS:METHOD-FUNCTION` `method`)`

Returns the method function of `method`. This is the value of the `:FUNCTION` initialization argument that was associated with the method during initialization.

#### 29.6.2.6. Methods

The specified methods for the method metaobject readers

`(`CLOS:METHOD-SPECIALIZERS` (`method` `STANDARD-METHOD`))`
`(`METHOD-QUALIFIERS` (`method` `STANDARD-METHOD`))`
`(`CLOS:METHOD-LAMBDA-LIST` (`method` `STANDARD-METHOD`))`
`(`CLOS:METHOD-FUNCTION` (`method` `STANDARD-METHOD`))`
  No behavior is specified for these methods beyond that which is specified for their respective generic functions.
`(`CLOS:METHOD-GENERIC-FUNCTION` (`method` `STANDARD-METHOD`))`

  No behavior is specified for this method beyond that which is specified for the generic function.

  The value returned by this method is maintained by ``ADD-METHOD`(`STANDARD-GENERIC-FUNCTION` `STANDARD-METHOD`)` and ``REMOVE-METHOD`(`STANDARD-GENERIC-FUNCTION` `STANDARD-METHOD`)`.

### 29.6.3. Initialization of Methods

#### 29.6.3.1. Macro `DEFMETHOD`

The evaluation or execution of a `DEFMETHOD` form requires first that the body of the method be converted to a method function. This process is described below. The result of this process is a method function and a set of additional initialization arguments to be used when creating the new method. Given these two values, the evaluation or execution of a `DEFMETHOD` form proceeds in three steps.

The first step ensures the existence of a generic function with the specified name. This is done by calling the function `ENSURE-GENERIC-FUNCTION`. The first argument in this call is the generic function name specified in the `DEFMETHOD` form.

The second step is the creation of the new method metaobject by calling `MAKE-INSTANCE`. The class of the new method metaobject is determined by calling `CLOS:GENERIC-FUNCTION-METHOD-CLASS` on the result of the call to `ENSURE-GENERIC-FUNCTION` from the first step.

The initialization arguments received by the call to `MAKE-INSTANCE` are as follows:

- The value of the `:QUALIFIERS` initialization argument is a list of the qualifiers which appeared in the `DEFMETHOD` form. No special processing is done on these values. The order of the elements of this list is the same as in the `DEFMETHOD` form.
- The value of the `:LAMBDA-LIST` initialization argument is the unspecialized lambda list from the `DEFMETHOD` form.
- The value of the `:SPECIALIZERS` initialization argument is a list of the specializers for the method. For specializers which are classes, the specializer is the class metaobject itself. In the case of `EQL` specializers, it will be an `CLOS:EQL-SPECIALIZER` metaobject obtained by calling `CLOS:INTERN-EQL-SPECIALIZER` on the result of evaluating the `EQL` specializer form in the lexical environment of the `DEFMETHOD` form.
- The value of the `:FUNCTION` initialization argument is the method function.

- The value of the `:DECLARATIONS` initialization argument is a list of the declaration specifiers from the `DEFMETHOD` form. If there are no declarations in the macro form, this initialization argument either does not appear, or appears with a value of the empty list.

  ### Implementation dependent: only in CLISP

  No `:DECLARATIONS` initialization argument is provided, because method initialization does not support a `:DECLARATIONS` argument, and because the method function is already completely provided through the `:FUNCTION` initialization argument.

- The value of the `:DOCUMENTATION` initialization argument is the documentation string from the `DEFMETHOD` form. If there is no documentation string in the macro form this initialization argument either does not appear, or appears with a value of false.
- Any other initialization argument produced in conjunction with the method function are also included.
- The implementation is free to include additional initialization arguments provided these are not symbols accessible in the “COMMON-LISP-USER” package, or exported by any package defined in the [ANSI CL standard].

In the third step, `ADD-METHOD` is called to add the newly created method to the set of methods associated with the generic function metaobject.

The result of the call to `ADD-METHOD` is returned as the result of evaluating or executing the `DEFMETHOD` form.

An example showing a typical `DEFMETHOD` form and a sample expansion is shown in the following example:

An example `DEFMETHOD` form and one possible correct expansion. In the expansion, `method-lambda` is the result of calling `CLOS:MAKE-METHOD-LAMBDA` as described in Section 29.6.3.1.1, “Processing Method Bodies”. The initargs appearing after `:FUNCTION` are assumed to be additional initargs returned from the call to `CLOS:MAKE-METHOD-LAMBDA`.

    (defmethod move :before ((p position) (l (eql 0))
                             &OPTIONAL (visiblyp t)
                             &KEY color)
      (set-to-origin p)
      (when visiblyp (show-move p 0 color)))

    (let ((#:g001 (ensure-generic-function 'move)))
      (add-method #:g001
        (make-instance (generic-function-method-class #:g001)
                       :qualifiers '(:before)
                       :specializers (list (find-class 'position)
                                           (intern-eql-specializer 0))
                       :lambda-list '(p l &OPTIONAL (visiblyp t)
                                          &KEY color)
                       :function (function method-lambda)
                       'additional-initarg-1 't
                       'additional-initarg-2 '39)))

The processing of the method body for this method is shown below.

##### 29.6.3.1.1. Processing Method Bodies

Before a method can be created, the list of forms comprising the method body must be converted to a method function. This conversion is a two step process.

### Note

The body of methods can also appear in the `:METHOD` option of `DEFGENERIC` forms. Initial methods are not considered by any of the protocols specified in this document.

During macro-expansion of the `DEFMETHOD` macro shown in the previous example code similar to this would be run to produce the method lambda and additional initargs. In this example, `environment` is the macroexpansion environment of the `DEFMETHOD` macro form.

    (let ((gf (ensure-generic-function 'move)))
      (make-method-lambda
        gf
        (class-prototype (generic-function-method-class gf))
        '(lambda (p l &OPTIONAL (visiblyp t) &KEY color)
           (set-to-origin p)
           (when visiblyp (show-move p 0 color)))
        environment))

The first step occurs during macro-expansion of the macro form. In this step, the method lambda list, declarations and body are converted to a lambda expression called a method lambda. This conversion is based on information associated with the generic function definition in effect at the time the macro form is expanded.

The generic function definition is obtained by calling `ENSURE-GENERIC-FUNCTION` with a first argument of the generic function name specified in the macro form. The `:LAMBDA-LIST` keyword argument is not passed in this call.

Given the generic function, production of the method lambda proceeds by calling `CLOS:MAKE-METHOD-LAMBDA`. The first argument in this call is the generic function obtained as described above. The second argument is the result of calling `CLOS:CLASS-PROTOTYPE` on the result of calling `CLOS:GENERIC-FUNCTION-METHOD-CLASS` on the generic function. The third argument is a lambda expression formed from the method lambda list, declarations and body. The fourth argument is the macro-expansion environment of the macro form; this is the value of the `&ENVIRONMENT` argument to the `DEFMETHOD` macro.

The generic function `CLOS:MAKE-METHOD-LAMBDA` returns two values. The first is the method lambda itself. The second is a list of initialization arguments and values. These are included in the initialization arguments when the method is created.

In the second step, the method lambda is converted to a function which properly captures the lexical scope of the macro form. This is done by having the method lambda appear in the macro-expansion as the argument of the `FUNCTION` special form. During the subsequent evaluation of the macro-expansion, the result of the `FUNCTION` special form is the method function.

### Implementation dependent: only in CLISP

See The generic function `CLOS:MAKE-METHOD-LAMBDA` is not implemented.

##### 29.6.3.1.2. Initialization of Generic Function and method metaobjects

An example of creating a generic function and a method metaobject, and then adding the method to the generic function is shown below. This example is comparable to the method definition shown above:

    (let* ((gf (make-instance 'standard-generic-function
                              :lambda-list '(p l &OPTIONAL visiblyp &KEY)))
           (method-class (generic-function-method-class gf)))
      (multiple-value-bind (lambda initargs)
           (make-method-lambda
             gf
             (class-prototype method-class)
             '(lambda (p l &OPTIONAL (visiblyp t) &KEY color)
                (set-to-origin p)
                (when visiblyp (show-move p 0 color)))
             nil)
        (add-method gf
                    (apply #'make-instance method-class
                           :function (compile nil lambda)
                           :specializers (list (find-class 'position)
                                               (intern-eql-specializer 0))
                           :qualifiers ()
                           :lambda-list '(p l &OPTIONAL (visiblyp t)
                                              &KEY color)
                           initargs))))

##### 29.6.3.1.3. Efficiency

###### Implementation dependent: only in CLISP and some other implementations

Methods created through `DEFMETHOD` have a faster calling convention than methods created through a portable `MAKE-INSTANCE` invocation.

#### 29.6.3.2. Initialization of method metaobjects

A method metaobject can be created by calling `MAKE-INSTANCE`. The initialization arguments establish the definition of the method. A method metaobject cannot be redefined; calling `REINITIALIZE-INSTANCE` `SIGNAL`s an `ERROR`.

Initialization of a method metaobject must be done by calling `MAKE-INSTANCE` and allowing it to call `INITIALIZE-INSTANCE`. Portable programs must not

- ... call `INITIALIZE-INSTANCE` directly to initialize a method metaobject;
- ... call `SHARED-INITIALIZE` directly to initialize a method metaobject;
- ... call `CHANGE-CLASS` to change the class of any method metaobject or to turn a non-method object into a method metaobject.

Since metaobject classes may not be redefined, no behavior is specified for the result of calls to `UPDATE-INSTANCE-FOR-REDEFINED-CLASS` on method metaobjects. Since the class of a method metaobject cannot be changed, no behavior is specified for the result of calls to `UPDATE-INSTANCE-FOR-DIFFERENT-CLASS` on method metaobjects.

During initialization, each initialization argument is checked for errors and then associated with the method metaobject. The value can then be accessed by calling the appropriate accessor as shown in Table 29.5, “Initialization arguments and accessors for method metaobjects”.

This section begins with a description of the error checking and processing of each initialization argument. This is followed by a table showing the generic functions that can be used to access the stored initialization arguments. The section ends with a set of restrictions on portable methods affecting method metaobject initialization.

In these descriptions, the phrase “this argument defaults to `value`” means that when that initialization argument is not supplied, initialization is performed as if `value` had been supplied. For some initialization arguments this could be done by the use of default initialization arguments, but whether it is done this way is not specified. Implementations are free to define default initialization arguments for specified method metaobject classes. Portable programs are free to define default initialization arguments for portable subclasses of the class `METHOD`.

- The `:QUALIFIERS` argument is a list of method qualifiers. An `ERROR` is `SIGNAL`ed if this value is not a proper list, or if any element of the list is not a non-null atom. This argument defaults to the empty list.
- The `:LAMBDA-LIST` argument is the unspecialized lambda list of the method. An `ERROR` is `SIGNAL`ed if this value is not a proper lambda list. If this value is not supplied, an `ERROR` is `SIGNAL`ed.
- The `:SPECIALIZERS` argument is a list of the specializer metaobjects for the method. An `ERROR` is `SIGNAL`ed if this value is not a proper list, or if the length of the list differs from the number of required arguments in the `:LAMBDA-LIST` argument, or if any element of the list is not a specializer metaobject. If this value is not supplied, an `ERROR` is `SIGNAL`ed.
- The `:FUNCTION` argument is a method function. It must be compatible with the methods on `CLOS:COMPUTE-EFFECTIVE-METHOD` defined for this class of method and generic function with which it will be used. That is, it must accept the same number of arguments as all uses of `CALL-METHOD` that will call it supply. (See `CLOS:COMPUTE-EFFECTIVE-METHOD` and `CLOS:MAKE-METHOD-LAMBDA` for more information.) An `ERROR` is `SIGNAL`ed if this argument is not supplied.
- When the method being initialized is an instance of a subclass of `CLOS:STANDARD-ACCESSOR-METHOD`, the `:SLOT-DEFINITION` initialization argument must be provided. Its value is the direct slot definition metaobject which defines this accessor method. An `ERROR` is `SIGNAL`ed if the value is not an instance of a subclass of `CLOS:DIRECT-SLOT-DEFINITION`.
- The `:DOCUMENTATION` argument is a string or `NIL`. An `ERROR` is `SIGNAL`ed if this value is not a string or `NIL`. This argument defaults to `NIL`.

After the processing and defaulting of initialization arguments described above, the value of each initialization argument is associated with the method metaobject. These values can then be accessed by calling the corresponding generic function. The correspondences are as follows:

Table 29.5. Initialization arguments and accessors for method metaobjects

Initialization Argument | Generic Function
--- | ---
`:QUALIFIERS` | `METHOD-QUALIFIERS`
`:LAMBDA-LIST` | `CLOS:METHOD-LAMBDA-LIST`
`:SPECIALIZERS` | `CLOS:METHOD-SPECIALIZERS`
`:FUNCTION` | `CLOS:METHOD-FUNCTION`
`:SLOT-DEFINITION` | `CLOS:ACCESSOR-METHOD-SLOT-DEFINITION`
`:DOCUMENTATION` | `DOCUMENTATION`

##### 29.6.3.2.1. Methods

It is not specified which methods provide the initialization behavior described above. Instead, the information needed to allow portable programs to specialize this behavior is presented in as a set of restrictions on the methods a portable program can define. The model is that portable initialization methods have access to the method metaobject when either all or none of the specified initialization has taken effect.

These restrictions govern the methods that a portable program can define on the generic functions `INITIALIZE-INSTANCE`, `REINITIALIZE-INSTANCE`, and `SHARED-INITIALIZE`. These restrictions apply only to methods on these generic functions for which the first specializer is a subclass of the class `METHOD`. Other portable methods on these generic functions are not affected by these restrictions.

- Portable programs must not define methods on `SHARED-INITIALIZE` or `REINITIALIZE-INSTANCE`.

- For `INITIALIZE-INSTANCE`:

  - Portable programs must not define primary methods.
  - Portable programs may define around-methods, but these must be extending, not overriding methods.
  - Portable before-methods must assume that when they are run, none of the initialization behavior described above has been completed.
  - Portable after-methods must assume that when they are run, all of the initialization behavior described above has been completed.

The results are undefined if any of these restrictions are violated.

### 29.6.4. Customization

#### 29.6.4.1. Function `CLOS:EXTRACT-LAMBDA-LIST`

Syntax
  `(`CLOS:EXTRACT-LAMBDA-LIST` `specialized-lambda-list`)`
Arguments
  `specialized-lambda-list`
    a specialized lambda list as accepted by `DEFMETHOD`.
Value
  An unspecialized lambda list.
Purpose

  This function takes a specialized lambda list and returns the lambda list with the specializers removed. This is a non-destructive operation. Whether the result shares any structure with the argument is unspecified.

  If the `specialized-lambda-list` argument does not have legal syntax, an `ERROR` is `SIGNAL`ed. This syntax checking does not check the syntax of the actual specializer names, only the syntax of the lambda list and where the specializers appear.

    (CLOS:EXTRACT-LAMBDA-LIST '((p position)))
    ⇒ (P)
    (CLOS:EXTRACT-LAMBDA-LIST '((p position) x y))
    ⇒ (P X Y)
    (CLOS:EXTRACT-LAMBDA-LIST '(a (b (eql x)) c &REST i))
    ⇒ (A B C &OPTIONAL I)

#### 29.6.4.2. Function `CLOS:EXTRACT-SPECIALIZER-NAMES`

Syntax
  `(`CLOS:EXTRACT-SPECIALIZER-NAMES` `specialized-lambda-list`)`
Arguments
  `specialized-lambda-list`
    a specialized lambda list as accepted by `DEFMETHOD`.
Value
  A list of specializer names.
Purpose

  This function takes a specialized lambda list and returns its specializer names. This is a non-destructive operation. Whether the result shares structure with the argument is unspecified.

  The list returned by this function will not be mutated by the implementation. The results are undefined if a portable program mutates the list returned by this function.

  The result of this function will be a list with a number of elements equal to the number of required arguments in `specialized-lambda-list`. Specializers are defaulted to the symbol `T`.

  If the `specialized-lambda-list` argument does not have legal syntax, an `ERROR` is `SIGNAL`ed. This syntax checking does not check the syntax of the actual specializer names, only the syntax of the lambda list and where the specializers appear.

    (CLOS:EXTRACT-SPECIALIZER-NAMES '((p position)))
    ⇒ (POSITION)
    (CLOS:EXTRACT-SPECIALIZER-NAMES '((p position) x y))
    ⇒ (POSITION T T)
    (CLOS:EXTRACT-SPECIALIZER-NAMES '(a (b (eql x)) c &REST i))
    ⇒ (T (EQL X) T)

| These notes document CLISP version 2.45 | Last modified: 2008-05-14

Enter your search termsSubmit search form
Webclisp.cons.orgclisp.podval.orgwww.lisp.org

Prev | Up | Next
29.5. Generic Functions | Home | 29.7. Accessor Methods