liveBook · Manning

Defprotocol

As explained in Clojure: The Essential Reference

defprotocol is a Clojure macro that defines a protocol interface supporting dynamic dispatch independently of Java class inheritance.

defprotocol defines a polymorphic interface whose functions dispatch on the type of their first argument. It combines a native Java interface with Clojure functions and an extension table, allowing behavior to vary independently of Java class inheritance. section 15.0 section 15.8

(defprotocol MyProtocol ; #1
  (method1 [this])
  (method2 [this]))

(pprint (vec (.getDeclaredMethods user.MyProtocol))) ; #2
;; [#object[Method "public abstract java.lang.Object user.MyProtocol.method1()"]
;;  #object[Method "public abstract java.lang.Object user.MyProtocol.method2()"]]

(pprint MyProtocol) ; #3

;; {:on user.MyProtocol,
;;  :on-interface user.MyProtocol,
;;  :sigs
;;  {:method1 {:name method1, :arglists ([this]), :doc nil},
;;   :method2 {:name method2, :arglists ([this]), :doc nil}},
;;  :var #'user/MyProtocol,
;;  :method-map {:method1 :method1, :method2 :method2},
;;  :method-builders
;;  {#'user/method2 #object["user$eval1675$fn__1676@6f9e2121"],
;;   #'user/method1 #object["user$eval1675$fn__1687@78d76411"]}}


(fn? method1) ; #4
;; true

(fn? method2)
;; true

Inspecting a protocol reveals its generated Java interface, method signatures, metadata, dispatch functions, and method builders. section 15.8

Declare, implement, and extend a protocol

(defprotocol MyProtocol (method1 [this]) (method2 [this])) (deftype MyProtocolImpl [] MyProtocol (method1 [this] "direct implementation")) (method1 (MyProtocolImpl.)) ;; "direct implementation" (extend java.lang.String MyProtocol {:method1 #(.toUpperCase %)}) (method1 "arg") ;; "ARG" A type can implement the protocol directly through deftype, defrecord, proxy, or reify, or an existing class can be extended with extend, extend-type, or related variants. Extending a type that already implements the protocol raises IllegalArgumentException. section 15.8

Dispatch and implementation details:

  • Each declared method becomes a Clojure function that selects an implementation from the actual class, metadata when enabled, or the extension table. section 15.8
  • Add :extend-via-metadata true to permit instance-specific implementations supplied through metadata. section 15.8
  • Direct interface implementation is reported as slightly faster than later extension in the supplied benchmark, though both approaches support the same polymorphic design. section 15.8

How Clojure: The Essential Reference covers it

How deep it goes
Explains declarations, generated artifacts, dispatch order, implementation routes, extension limits, metadata, and comparative dispatch timing.
Examples
Uses MyProtocol, method1, String extension, deftype implementation, metadata dispatch, generated methods, and dispatch benchmarks.
What it assumes
Assumes familiarity with Clojure functions and types while showing the protocol mechanism and implementation choices explicitly.
What you can do after
Build polymorphic interfaces, implement them directly, extend existing classes, and provide instance-specific behavior through metadata.
How it connects
Connects dynamic dispatch with Java interfaces, defrecord, deftype, proxy, reify, extend-type, and metadata.

Related concepts

This explainer was generated by Manning's knowledge graph from the text of Clojure: The Essential Reference. The section links point to the parts of the book it draws on.