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…