Protocols
Type of the first argument Any function of all arguments Very fast (JVM interfaces/caching) Slower (dispatch function + lookup) derive hierarchies Several related functions
;; Protocols: fast, type-based (single dispatch on the first argument), like interfaces
(defprotocol Shape
(area [this] "Compute the area.")
(perimeter [this]))
(defrecord Circle [r]
Shape
(area [_] (* Math/PI r r))
(perimeter [_] (* 2 Math/PI r)))
(defrecord Rect [w h]
Shape
(area [_] (* w h))
(perimeter [_] (* 2 (+ w h))))
(map area [(->Circle 1) (->Rect 2 3)]) ; (3.141592653589793 6)
;; Extend existing types (even Java classes and nil) without modifying them
(defprotocol Describable
(describe [x]))
(extend-protocol Describable
String (describe [s] (str "String of length " (count s)))
Long (describe [n] (str "Number " n))
clojure.lang.IPersistentMap (describe [m] (str "Map with " (count m) " keys"))
nil (describe [_] "nothing"))
(describe "hi") ; "String of length 2"
(describe nil) ; "nothing"
;; extend with a map of functions (reusable implementations)
(extend Rect
Describable
{:describe (fn [r] (str "Rect " (:w r) "x" (:h r)))})
(satisfies? Shape (->Circle 1)) ; true
(extends? Describable String) ; true
;; Metadata-based extension (1.10+)
…