Skip to content
Protocols and Records
step 1/5

Reading — step 1 of 5

Learn

~1 min readPolymorphism

Protocols are like Java interfaces with a Clojure twist — defined separately from the types that implement them.

(defprotocol Shape
    (area [s])
    (perimeter [s]))

(defrecord Circle [radius]
    Shape
    (area [_] (* Math/PI radius radius))
    (perimeter [_] (* 2 Math/PI radius)))

(defrecord Square [side]
    Shape
    (area [_] (* side side))
    (perimeter [_] (* 4 side)))

(area (Circle. 5))        ; ~78.54
(area (Square. 4))        ; 16

defrecord creates a Java class — fast field access, structural equality, automatic destructuring with :keys.

let c = (Circle. 5)
(:radius c)               ; 5 — like a map
(.radius c)               ; 5 — direct field access (faster)

Extending a protocol to existing types retroactively:

(extend-protocol Shape
    Long
    (area [n] (* n n))            ; treat any long as a square's side
    (perimeter [n] (* 4 n)))

(area 5)                  ; 25

vs multimethods:

  • Protocols dispatch only on the FIRST argument's type
  • Protocols are faster (uses Java polymorphism under the hood)
  • Multimethods are more flexible (dispatch on anything)

Use protocols for type-driven polymorphism. Use multimethods when you need flexible dispatch.

Use reify for one-off implementations:

let anonymous-shape (reify Shape
    (area [_] 42)
    (perimeter [_] 17))

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…