Given a set, map and vector in Clojure implement both IPersistentCollection and IFn, how does Clojure decide which implementation of SayHi 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
Protocol dispatch is done on the type of the first argument of the function. When multiple implementations match the type of the first argument, the most specific implementation is chosen. That is why the (hi #{})
call resolves to the set implementation and not the collection or fn implementations even though a set (#{}
) implements both of those.
The find-protocol-impl
function in the clojure-deftype.clj
seems to handle the protocol to implementing 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)))))))
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