Clojure is written in terms of abstractions. There are abstractions for sequences, collections, callability, etc. In addition, Clojure supplies many implementations of these abstractions. The abstractions are specified by host interfaces, and the implementations by host classes. While this was sufficient for bootstrapping the language, it left Clojure without similar abstraction and low-level implementation facilities. The protocols and datatypes features add powerful and flexible mechanisms for abstraction and data structure definition with no compromises vs the facilities of the host platform.

There are several motivations for protocols:

Support the 90% case of multimethods (single dispatch on type) while providing higher-level abstraction/organization

do so without wrappers/adapters

Avoid the 'expression problem' by allowing independent extension of the set of types, protocols, and implementations of protocols on types, by different parties

implementing an interface creates an isa/instanceof type relationship and hierarchy

Which interfaces are implemented is a design-time choice of the type author, cannot be extended later (although interface injection might eventually address this)

While avoiding some of the drawbacks

Support the best parts of interfaces

Provide a high-performance, dynamic polymorphism construct as an alternative to interfaces

Basics

A protocol is a named set of named methods and their signatures, defined using defprotocol:

(defprotocol AProtocol "A doc string for AProtocol abstraction" (bar [a b] "bar docs") (baz [a] [a b] [a b c] "baz docs"))

No implementations are provided

Docs can be specified for the protocol and the functions

The above yields a set of polymorphic functions and a protocol object all are namespace-qualified by the namespace enclosing the definition

The resulting functions dispatch on the type of their first argument, and thus must have at least one argument

defprotocol is dynamic, and does not require AOT compilation

defprotocol will automatically generate a corresponding interface, with the same name as the protocol, e.g. given a protocol my.ns/Protocol, an interface my.ns.Protocol. The interface will have methods corresponding to the protocol functions, and the protocol will automatically work with instances of the interface.

Note that you do not need to use this interface with deftype , defrecord , or reify, as they support protocols directly:

(defprotocol P (foo [x]) (bar-me [x] [x y])) (deftype Foo [a b c] P (foo [x] a) (bar-me [x] b) (bar-me [x y] (+ c y))) (bar-me (Foo. 1 2 3) 42) = > 45 (foo (let [x 42] (reify P (foo [this] 17) (bar-me [this] x) (bar-me [this y] x)))) > 17

A Java client looking to participate in the protocol can do so most efficiently by implementing the protocol-generated interface.

External implementations of the protocol (which are needed when you want a class or type not in your control to participate in the protocol) can be provided using the extend construct:

(extend AType AProtocol {:foo an-existing-fn :bar (fn [a b] ...) :baz (fn ([a]...) ([a b] ...)...)} BProtocol {...} ...)

extend takes a type/class (or interface, see below), a one or more protocol + function map (evaluated) pairs.

Will extend the polymorphism of the protocol’s methods to call the supplied functions when an AType is provided as the first argument

Function maps are maps of the keywordized method names to ordinary fns this facilitates easy reuse of existing fns and maps, for code reuse/mixins without derivation or composition

You can implement a protocol on an interface this is primarily to facilitate interop with the host (e.g. Java) but opens the door to incidental multiple inheritance of implementation since a class can inherit from more than one interface, both of which implement the protocol if one interface is derived from the other, the more derived is used, else which one is used is unspecified.

The implementing fn can presume first argument is instanceof AType

You can implement a protocol on nil

To define a default implementation of protocol (for other than nil) just use Object

Protocols are fully reified and support reflective capabilities via extends? , extenders , and satisfies? .

Note the convenience macros extend-type and extend-protocol

If you are providing external definitions inline, these will be more convenient than using extend directly