1.3.0 permalink Arrow_down_16x16

defprotocol

clojure.core

  • (defprotocol name & opts+sigs)
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

4 Examples top

  • (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..."
  • ;; 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))))
    
  • ;; 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))
  • ;; 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))))
    
    
    user=> (require '[abstraction-a :as a])
    
    user=> (require '[abstraction-b :as b])
    
    user=> (a/foo "Bar")
    "foo-A-BAR"
    
    user=> (b/foo "Bar")
    "foo-B-bar"
    
    user=> (a/foo nil)
    "foo-A!"
    
    user=> (b/foo nil)
    "foo-B!"
    
Log in to add / edit an example.

See Also top

Log in to add a see also.

Plus_12x12 Minus_12x12 Source clojure/core_deftype.clj:600 top

(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))
Vars in clojure.core/defprotocol:
Used in 0 other vars

Comments top

No comments for defprotocol. Log in to add a comment.