Enabling Clojure Calls When a Class Implements Multiple Interfaces

Given that the set, map, and vector in Clojure implement both IPersistentCollection and IFn, Clojure decides which SayHi implementation to use:

(defprotocol SayHi
  (hi [this]))

(extend-protocol SayHi
  clojure.lang.IPersistentCollection
  (hi [_] (println "Hi from collection"))
  clojure.lang.IFn
  (hi [_] (println "Hi from Fn!"))
  clojure.lang.IPersistentSet
  (hi [_] (println "Hi from set!")))

(hi #{})
Hi from set!
(hi [])
Hi from collection
+5
source share
1 answer

Sending a protocol is performed as the first argument of the function. When multiple implementations match the type of the first argument, the most specific implementation is selected. This is why the call (hi #{})allows the implementation of the collection, not the implementation of the collection or fn, even if the collection ( #{}) implements both of these files.

Function find-protocol-implin clojure-deftype.cljseems to process the protocol to implement object resolution:

(defn find-protocol-impl [protocol x]
  (if (instance? (:on-interface protocol) x)
    x
    (let [c (class x)
          impl #(get (:impls protocol) %)]
      (or (impl c)
          (and c (or (first (remove nil? (map impl (butlast (super-chain c)))))
                     (when-let [t (reduce1 pref (filter impl (disj (supers c) Object)))]
                       (impl t))
                     (impl Object)))))))
+5
source

All Articles