Often when I see clojure protocols in a library, the protocol methods will be wrapped in a function, often with little added functionality. e.g.:
(defprotocol Pfoo
(foo-method [this]))
(deftype Atype [x y]
Pfoo
(foo-method [this] (do-something)))
(defn foo [arg] (foo-method arg))
And clients are generally expected to call the function foo, rather than the foo-method from the protocol. (See the protocols at the top of clojurescript core for concrete examples of this kind of thing.
So why are protocols often shielded behind functions? Couldn't the protocol method become the client-facing part, rather than the wrapping function?
Protocols represent an interface point between two kinds of concrete entities. One is the code calling the protocol (anything that calls foo
in your example), the other is the code implementing it (Atype
foo-method
). What is convenient for one may not be convenient for the other. An implementer wants to provide the smallest interface that is complete, while callers want the richest API that can be supported.
You mentioned ClojureScript core; take a look at the ISeq
protocol there. It is implemented by several types, each of which must implement -first
and -rest
. To make these as easy as possible to implement, neither is required to call seq on its arg. However, the related functions first
and rest
that face callers support passing in non-seqs like strings, vectors, etc. so this common functionality is provided by the non-protocol functions.Of course the caller-facing API is even richer than that with next
, map
, filter
, sequential destructuring, etc all built on top of -first
and -rest
.
Other common features provided by fns that wrap protocol methods include argument validation (such as asserts), default arguments, and support for var-args.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With