Inheritance and Multiple Dispatch

32.1 Inheritance

The class precedence list (C3-like linearization defined by the standard) determines which method is most specific.

(defclass animal ()
  ((name :initarg :name :accessor name)
   (sound :initform "..." :accessor sound)))

(defclass dog (animal)
  ((sound :initform "Woof")            ; override a slot default
   (breed :initarg :breed :initform "mixed" :accessor breed)))

(defclass cat (animal)
  ((sound :initform "Meow")))

(defgeneric speak (animal))
(defmethod speak ((a animal))
  (format nil "~a says ~a" (name a) (sound a)))
(defmethod speak ((d dog))
  (concatenate 'string (call-next-method) " (wags tail)"))   ; call the less specific method

(mapcar #'speak (list (make-instance 'dog :name "Rex") (make-instance 'cat :name "Tom")))
;; ("Rex says Woof (wags tail)" "Tom says Meow")

;; Multiple inheritance with mixins
(defclass swimmer () ())
(defclass flyer () ())
(defclass duck (animal swimmer flyer) ((sound :initform "Quack")))
(defmethod move ((s swimmer)) "swims")
(sb-mop:class-precedence-list (find-class 'duck))   ; DUCK ANIMAL SWIMMER FLYER STANDARD-OBJECT T (via MOP)

32.2 Multiple Dispatch

Multiple dispatch removes the need for the Visitor pattern and double-dispatch hacks.

;; Methods can specialize on MORE THAN ONE argument
(defclass asteroid () ())
(defclass spaceship () ())

(defgeneric collide (a b))
(defmethod collide ((a asteroid) (b asteroid)) "Asteroids bounce off each other")
(defmethod collide ((a asteroid) (b spaceship)) "Spaceship destroyed by asteroid")
(defmethod collide ((a spaceship) (b asteroid)) (collide b a))
(defmethod collide ((a spaceship) (b spaceship)) "Spaceships dock")

(collide (make-instance 'spaceship) (make-instance 'asteroid))   ; "Spaceship destroyed by asteroid"