store/[org.clojure/clojure "1.8.0"] clj::clojure.core/defprotocol

Official Documentation

Add notes
Arities
==================================================
   [name & opts+sigs]

Docstring
==================================================
  A protocol is a named set of named methods and their signatures:
  (defprotocol AProtocolName

    ;optional doc string
    "A doc string for AProtocol abstraction"

  ;method signatures
    (bar [this a b] "bar docs")
    (baz [this a] [this a b] [this a b c] "baz docs"))

  No implementations are provided. Docs can be specified for the
  protocol overall and for each method. The above yields a set of
  polymorphic functions and a protocol object. All are
  namespace-qualified by the ns enclosing the definition The resulting
  functions dispatch on the type of their first argument, which is
  required and corresponds to the implicit target object ('this' in 
  Java parlance). defprotocol is dynamic, has no special compile-time 
  effect, and defines no new types or classes. Implementations of 
  the protocol methods can be provided using extend.

  defprotocol will automatically generate a corresponding interface,
  with the same name as the protocol, i.e. 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 should not use this interface with deftype or
  reify, as they support the protocol directly:

  (defprotocol P 
    (foo [this]) 
    (bar-me [this] [this y]))

  (deftype Foo [a b c] 
   P
    (foo [this] a)
    (bar-me [this] b)
    (bar-me [this 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

Source

(defmacro defprotocol 
  "A protocol is a named set of named methods and their signatures:
  (defprotocol AProtocolName

    ;optional doc string
    \"A doc string for AProtocol abstraction\"

  ;method signatures
    (bar [this a b] \"bar docs\")
    (baz [this a] [this a b] [this a b c] \"baz docs\"))

  No implementations are provided. Docs can be specified for the
  protocol overall and for each method. The above yields a set of
  polymorphic functions and a protocol object. All are
  namespace-qualified by the ns enclosing the definition The resulting
  functions dispatch on the type of their first argument, which is
  required and corresponds to the implicit target object ('this' in 
  Java parlance). defprotocol is dynamic, has no special compile-time 
  effect, and defines no new types or classes. Implementations of 
  the protocol methods can be provided using extend.

  defprotocol will automatically generate a corresponding interface,
  with the same name as the protocol, i.e. 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 should not use this interface with deftype or
  reify, as they support the protocol directly:

  (defprotocol P 
    (foo [this]) 
    (bar-me [this] [this y]))

  (deftype Foo [a b c] 
   P
    (foo [this] a)
    (bar-me [this] b)
    (bar-me [this 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"
  {:added "1.2"} 
  [name & opts+sigs]
  (emit-protocol name opts+sigs))

Example 1

Edit
;; from Stuart Halloway's examples:

(defprotocol Player
  (choose [p])
  (update-strategy [p me you]))

(defrecord Stubborn [choice]
  Player
  (choose [_] choice)
  (update-strategy [this _ _] this))

(defrecord Mean [last-winner]
  Player
  (choose [_]
    (if last-winner
      last-winner
      (random-choice)))
  (update-strategy [_ me you]
    (->Mean (when (iwon? me you) me))))

Example 2

Edit
;; Protocols allow you to add new abstractions to existing types in a clean way.
;; Polymorphic functions are created in namespaces as opposed to
;; having the polymorphism live on Classes as typically done in OO.

;; example from: 
;; https://speakerdeck.com/bmabey/clojure-plain-and-simple?slide=230
(ns abstraction-a)

(defprotocol AbstractionA
  (foo [obj]))

(extend-protocol AbstractionA
  nil
  (foo [s] (str "foo-A!"))
  String
  (foo [s] (str "foo-A-" (.toUpperCase s))))

(ns abstraction-b)

(defprotocol AbstractionB
  (foo [obj]))

(extend-protocol AbstractionB
  nil
  (foo [s] (str "foo-B!"))
  String
  (foo [s] (str "foo-B-" (.toLowerCase s))))

(require '[abstraction-a :as a])

(require '[abstraction-b :as b])

(a/foo "Bar")
;; => "foo-A-BAR"

(b/foo "Bar")
;; => "foo-B-bar"

(a/foo nil)
;; => "foo-A!"

(b/foo nil)
;; => "foo-B!"

Example 3

Edit
;; defprotocol does NOT support interfaces with variable argument lists, 
;; like [this & args]
;; (this is not documented anywhere... )

;; The workaround is to define the interface with the variable arg list in a fn
;; separately outside of the protocol, which then calls the protocol interface
;; with a slightly different name and an array in place of the variable list,
;; like:

(defprotocol MyProtocol
  (-my-fn [this args]))

(defn my-fn [this & args] (-my-fn this args))

Example 4

Edit
(defprotocol Fly
  "A simple protocol for flying"
  (fly [this] "Method to fly"))

(defrecord Bird [name species]
  Fly
  (fly [this] (str (:name this) " flies...")))

(extends? Fly Bird)
-> true

(def crow (Bird. "Crow" "Corvus corax"))

(fly crow)
-> "Crow flies..."

Uses on crossclj