Earlier quoted context omitted.
multi-methods at least are isa?-based. This implies that they obey ad-hoc hierarchies created via derive as well as traditional java inheritance hierarchies. protocols are little more than open-ended interfaces (i.e. I can extend them at run-time to my things and to other things).
Just a slight addendum: Clojure multimethods can resolve to a concrete method implementation based on any function of their parameters. So, in addition to single dispatch based on class (a la Java), you could also dispatch based on the classes of multiple parameters or on the value of the field 3 objects deep.
This means that you can do something like
(defmulti cares-about-a-and-c
"multimethod that cares about the first and third args"
(fn [a b c] [a c]))
(defmethod cares-about-a-and-c [:alpha :gamma]
[a b c]
(prn "got :alpha and :gamma"))
(defmethod cares-about-a-and-c [1 3]
[a b c]
(prn "got 1 and 3"))
but the following won't really work how you want it to: (defmethod cares-about-a-and-c [String String]
[a b c]
(prn "Got two things that match (isa? String)"))
(cares-about-a-and-c "foo" nil "bar") ;; doesn't call our last method
You could, however, define something based on class and not isa? via your dispatch function: (defmulti cares-about-class-of-a-and-c
""
(fn [a b c] (mapv class [a c])))
(defmethod cares-about-class-of-a-and-c [String String]
[a _ c]
(println "Got the strings: " a " and " c))