Skip to main content

call-next-method

call-next-method Local Function

Syntax:

call-next-method &rest args → {result}*

Arguments and Values:

arg—an object.

results—the values returned by the method it calls.

Description:

The function call-next-method can be used within the body forms (but not the lambda list) of a method defined by a method-defining form to call the next method.

If there is no next method, the generic function no-next-method is called.

The type of method combination used determines which methods can invoke call-next-method. The standard method combination type allows call-next-method to be used within primary methods and around methods. For generic functions using a type of method combination defined by the short form of define-method-combination, call-next-method can be used in around methods only.

When call-next-method is called with no arguments, it passes the current method’s original arguments to the next method. Neither argument defaulting, nor using setq, nor rebinding variables with the same names as parameters of the method affects the values call-next-method passes to the method it calls.

When call-next-method is called with arguments, the next method is called with those arguments.

If call-next-method is called with arguments but omits optional arguments, the next method called defaults those arguments.

The function call-next-method returns any values that are returned by the next method.

The function call-next-method has lexical scope and indefinite extent and can only be used within the body of a method defined by a method-defining form.

Whether or not call-next-method is fbound in the global environment is implementation-dependent; however, the restrictions on redefinition and shadowing of call-next-method are the same as for symbols in the COMMON-LISP package which are fbound in the global environment. The consequences of attempting to use call-next-method outside of a method-defining form are undefined.

Affected By:

defmethod, call-method, define-method-combination.

Exceptional Situations:

When providing arguments to call-next-method, the following rule must be satisfied or an error of type error should be signaled: the ordered set of applicable methods for a changed set of arguments for call-next-method must be the same as the ordered set of applicable methods for the original arguments to the generic function. Optimizations of the error checking are possible, but they must not change the semantics of call-next-method.

See Also:

define-method-combination, defmethod, next-method-p, no-next-method, call-method, Section 7.6.6 (Method Selection and Combination), Section 7.6.6.2 (Standard Method Combination), Section 7.6.6.4 (Built-in Method Combination Types)

Expanded Reference: call-next-method

Basic Usage in Primary Methods

call-next-method invokes the next most specific method in the method chain. When called with no arguments, it passes the original arguments.

(defclass animal ()
((name :initarg :name :accessor animal-name)))

(defclass dog (animal) ())

(defgeneric describe-it (thing))

(defmethod describe-it ((a animal))
(format nil "Animal: ~A" (animal-name a)))

(defmethod describe-it ((d dog))
(format nil "Dog! ~A" (call-next-method)))

(describe-it (make-instance 'dog :name "Rex"))
=> "Dog! Animal: Rex"

Building Results Through the Chain

Each method in the chain can contribute to the final result by combining its own logic with the result of call-next-method.

(defclass base () ())
(defclass middle (base) ())
(defclass top (middle) ())

(defgeneric get-layers (obj))

(defmethod get-layers ((obj base))
(list :base))

(defmethod get-layers ((obj middle))
(cons :middle (call-next-method)))

(defmethod get-layers ((obj top))
(cons :top (call-next-method)))

(get-layers (make-instance 'top))
=> (:TOP :MIDDLE :BASE)

Using call-next-method in :around Methods

In :around methods, call-next-method is used to invoke the rest of the method combination (including other :around methods, :before methods, the primary method, and :after methods).

(defgeneric process (item))

(defmethod process ((item string))
(string-upcase item))

(defmethod process :around ((item string))
(format nil "[~A]" (call-next-method)))

(process "hello")
=> "[HELLO]"

Passing Different Arguments

You can pass explicit arguments to call-next-method. The new arguments must produce the same set of applicable methods as the original arguments.

(defgeneric transform (x))

(defmethod transform ((x integer))
(* x 10))

(defmethod transform :around ((x integer))
(if (< x 0)
(call-next-method (- x)) ;; Pass the absolute value
(call-next-method)))

(transform -5)
=> 50
(transform 3)
=> 30

Conditional Delegation

A method can test conditions before deciding whether to delegate to the next method.

(defclass cacheable ()
((cache :initform (make-hash-table) :accessor obj-cache)))

(defgeneric compute (obj key))

(defmethod compute ((obj cacheable) key)
(* key key))

(defmethod compute :around ((obj cacheable) key)
(let ((cached (gethash key (obj-cache obj))))
(or cached
(let ((result (call-next-method)))
(setf (gethash key (obj-cache obj)) result)
result))))

(let ((obj (make-instance 'cacheable)))
(list (compute obj 5) (compute obj 5)))
=> (25 25)