πCommon Lisp: Multiple Dispatch
Primary methods
;; Define the generic function first.
(defgeneric draw (shape)
(:documentation "docstring."))
;; Next, define methods (i.e., generic function implementations)
(defmethod draw ((shape circle))
...)
(defmethod draw ((shape triangle))
...)
;; If there are multiple matching, a method can call
;; `call-next-method' to execute the next implementation.
(defmethod withdraw ((account checking-account) amount)
...some code...
(call-next-method))
Auxiliary methods
Common Lisp has primary and auxiliary methods. Auxiliary methods can be defined with :before
, :after
, and :around
specifiers.
(defmethod withdraw :before ((account bank-account) amount) ...)
(defmethod withdraw :after ((account bank-account) amount) ...)
(defmethod withdraw :around ((account bank-account) amount) ...)
Execution order:
All around methods in the order from most specific to less specific. Around methods should call
call-next-method
.When the least specific around method calls
call-next-method
, that executes:All before methods in the order from most specific to least specific.
Primary method.
Primary method may call
call-next-method
to execute the next less specific primary method.
All after methods in the order from least specific to most specific (reverse order of before).
Method combinations
Be default, primary methods completely override less specific primary methods (although they can be executed with call-next-method
). Common Lisp also has nine other combinations: +
, and
, or
, list
, append
, nconc
, min
, max
, and progn
βthey wrap all primary methods in the specified function/macro/operator. (New method combinations can be added with define-method-combination
.)
If method combination is used, only primary and :around
methods are supported.
(defgeneric priority (job)
(:method-combination +))
;; :most-specific-last can be added to reverse the order of primary
;; methods (does not affect :around methods)
;; `defmethod' must also specify the method combination.
(defmethod priority + ((job express-job))
10)
eql
specializer
It is possible to create methods that specialize on a particular object with an eql
specializer.
(defmethod withdraw ((account (eql *account-of-bank-president*)) amount)
...)
The object in eql
specializer is evaluated once only (i.e., if the value of that variable changes, the method wonβt change).