Multimethods and Hierarchies
;; Dispatch on ANY function of the arguments
(defmulti area :shape) ; dispatch function: the :shape key
(defmethod area :circle [{:keys [r]}] (* Math/PI r r))
(defmethod area :rect [{:keys [w h]}] (* w h))
(defmethod area :default [shape] (throw (ex-info "Unknown shape" {:shape shape})))
(area {:shape :circle :r 1}) ; 3.141592653589793
(area {:shape :rect :w 2 :h 3}) ; 6
;; Multiple dispatch: on several values
(defmulti collide (fn [a b] [(:type a) (:type b)]))
(defmethod collide [:asteroid :ship] [_ _] "ship destroyed")
(defmethod collide [:ship :asteroid] [a b] (collide b a))
(defmethod collide :default [_ _] "nothing happens")
(collide {:type :ship} {:type :asteroid}) ; "ship destroyed"
;; Dispatch on class or value
(defmulti describe class)
(defmethod describe String [s] (str "string: " s))
(defmethod describe Number [n] (str "number: " n))
(describe 42) ; "number: 42" (Long isa Number)
;; Ad hoc hierarchies with derive
(derive ::dog ::animal)
(derive ::cat ::animal)
(defmulti speak :kind)
(defmethod speak ::animal [_] "generic animal noise")
(defmethod speak ::dog [_] "Woof")
(s
…