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+)
…