Method Combination
33.1 Standard Method Combination: before, after, around
Most specific first, outermost Must call call-next-method to continue Most specific first Return values ignored
Most specific first; call-next-method goes to the next Provides the return value Least specific first
(defclass account ()
((balance :initarg :balance :initform 0 :accessor balance)))
(defgeneric withdraw (account amount))
(defmethod withdraw ((acc account) amount) ; primary method
(decf (balance acc) amount))
(defmethod withdraw :before ((acc account) amount) ; runs before the primary methods
(when (> amount (balance acc))
(error "Insufficient funds: balance ~a, requested ~a" (balance acc) amount)))
(defmethod withdraw :after ((acc account) amount) ; runs after
(format t "~&Withdrew ~a, new balance ~a~%" amount (balance acc)))
(defmethod withdraw :around ((acc account) amount) ; wraps everything
(format t "~&[audit] starting withdrawal~%")
(let ((result (call-next-method))) ; continue to before/primary/after
(format t "~&[audit] done~%")
result))
(withdraw (make-instance 'account :balance 100) 30)
;; [audit] starting withdrawal
;; Withdrew 30, new balance 70
;; [audit] done33.2 Built-in and Custom Method Combinations
(defgeneric total-price (item) (:method-combination +)) ; sum the results of all applicable methods
(defclass product () ())
(defclass taxed (product) ())
(defmethod total-price + ((p product)) 100)
(defmethod total-price + ((p taxed)) 18)
(total-price (make-instance 'taxed)) ; 118
(defgeneric describe-features (obj) (:method-combination list))
(defmethod describe-features list ((p product)) :basic)
(defmethod describe-features list ((p taxed)) :taxed)
(describe-features (make-instance 'taxed)) ; (:TAXED :BASIC)
;; Other built-in combinations: progn, and, or, append, nconc, max, min
;; define-method-combination creates your own (short or long form)
(defun concatenate-strings (&rest strings) (apply #'concatenate 'string strings))
(define-method-combination concatenate-strings) ; short form: the operator defaults to the same name
(defgeneric label (obj) (:method-combination concatenate-strings))
(defmethod label concatenate-strings ((p product)) "product")
(defmethod label concatenate-strings ((p taxed)) "taxed-")
(label (make-instance 'taxed)) ; "taxed-product"