29.6. Methods

29.6.1. Inheritance Structure of method metaobject Classes
29.6.2. Introspection: Readers for method metaobjects
29.6.2.1. Generic Function CLOS:METHOD-SPECIALIZERS
29.6.2.2. Generic Function METHOD-QUALIFIERS
29.6.2.3. Generic Function CLOS:METHOD-LAMBDA-LIST
29.6.2.4. Generic Function CLOS:METHOD-GENERIC-FUNCTION
29.6.2.5. Generic Function CLOS:METHOD-FUNCTION
29.6.2.6. Methods
29.6.3. Initialization of Methods
29.6.3.1. Macro DEFMETHOD
29.6.3.1.1. Processing Method Bodies
29.6.3.1.2. Initialization of Generic Function and method metaobjects
29.6.3.1.3. Efficiency
29.6.3.2. Initialization of method metaobjects
29.6.3.2.1. Methods
29.6.4. Customization
29.6.4.1. Function CLOS:EXTRACT-LAMBDA-LIST
29.6.4.2. Function CLOS:EXTRACT-SPECIALIZER-NAMES

29.6.1. Inheritance Structure of method metaobject Classes

Figure 29.5. Inheritance structure of method metaobject classes

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 SIGNALed. An ERROR is also SIGNALed 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

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

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

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.

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

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 SIGNALs 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

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 SIGNALed 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 SIGNALed if this value is not a proper lambda list. If this value is not supplied, an ERROR is SIGNALed.
  • The :SPECIALIZERS argument is a list of the specializer metaobjects for the method. An ERROR is SIGNALed 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 SIGNALed.
  • 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 SIGNALed 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 SIGNALed 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 SIGNALed 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 ArgumentGeneric Function
:QUALIFIERSMETHOD-QUALIFIERS
:LAMBDA-LISTCLOS:METHOD-LAMBDA-LIST
:SPECIALIZERSCLOS:METHOD-SPECIALIZERS
:FUNCTIONCLOS:METHOD-FUNCTION
:SLOT-DEFINITIONCLOS:ACCESSOR-METHOD-SLOT-DEFINITION
:DOCUMENTATIONDOCUMENTATION


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 SIGNALed. 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 SIGNALed. 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.49.93+Last modified: 2018-02-19