What is the difference between defmethod & defmulti??
Referred to these links. But its still not clear..
Can someone please help me with the simple example?
There are already similar questions on SO - this one in particular I think might be helpful: What are the benefits of using multimethods instead of cond in Clojure?
Multimethods are one of the mechanisms Clojure provides for implementing polymorphic behavior.
Unlike protocols, that only dispatch on the type of the first argument of the protocol's functions, multimethods allow for arbitrary dispatch via a dispatch function that you provide with defmulti.
That means defmulti defines a new multimethod - its name, docstring, and, in particular, the dispatch function.
But it does not define any implementation on its own - it's like an interface with a single method/function.
In contrast, defmethod is used to implement the multimethod for a particular value returned by the dispatch function.
One important thing to understand is that the dispatch function of defmulti takes the exact same arguments as the multimethod's implementations.
You can also provide a default implementation that gets called if the value returned by the dispatch function does not match any of the existing implementations. You do this via (defmethod my-multi-method :default ...).
There are numerous examples out there and I recommend you check some of the Clojure books explaining this in detail - e.g. Programming Clojure, Third edition dedicates the whole chapter 9 to multimethods.
Joy of Clojure (an excellent and deep book about Clojure in general) also has some good examples, including compiler in chapter 9 - I have the examples published here: https://github.com/jumarko/clojure-experiments/blob/develop-performance/src/clojure_experiments/books/joy_of_clojure/ch09_data_and_code.clj#L144-L158
(it also mentions some more complicated concepts like hierarchies - see derive - but that is not necessary for you to understand at this time).
Another good example of using multimethods is Clojure itself, e.g. print-method. It is defined in clojure.core :https://github.com/clojure/clojure/blob/clojure-1.11.1/src/clj/clojure/core.clj#L3664-L3666
(defmulti print-method (fn [x writer]
(let [t (get (meta x) :type)]
(if (keyword? t) t (class x)))))
You can see that this multimethod basically dispatches on the type/class of its first argument.
It is then implemented in numerous places, notably core_print.clj. E.g. for keywords, it's implemented like this:
(defmethod print-method clojure.lang.Keyword [o, ^Writer w]
(.write w (str o)))
Another good example is instant.clj which provides a few print-method implementations for date-related types.
print-method also has the default implementation
(defmethod print-method :default [o, ^Writer w]
(if (instance? clojure.lang.IObj o)
(print-method (vary-meta o #(dissoc % :type)) w)
(print-simple o w)))
Having print-method defined as a multimethod not only allows Clojure itself to separate implementations for various types but also provides an "open extension" mechanism for the users of the language.
That is you can implement print-method for your custom types to print them nicely.
One example of this is the clj-time library
;; pr and prn support to write edn
(defmethod print-method org.joda.time.DateTime
[v ^java.io.Writer w]
(.write w (to-edn v)))
Finally, a small tip: defmulti uses defonce under the hood so to redefine its definition (the dispatch function) while you are working on it, you can use this trick:
(def my-multi-method nil)
(defmulti my-multi-method ...)
The first def will make sure to replace whatever my-multi-method points to so you can get the fresh definition without restarting the REPL.
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