Search code examples
clojuremultimethod

defmethod catch all


I have a multimethod that specializes on two parameters:

(defmulti get-tag-type (fn [type tag] [type tag]))

Having the type allows me to group the different defmethod calls into sets:

(defmethod get-tag-type [::cat 0] [type tag] ::tiger)
(defmethod get-tag-type [::cat 1] [type tag] ::lion)
(defmethod get-tag-type [::cat 2] [type tag] ::jaguar)

(defmethod get-tag-type [::dog 0] [type tag] ::poodle)
(defmethod get-tag-type [::dog 1] [type tag] ::australian-shepherd)
(defmethod get-tag-type [::dog 2] [type tag] ::labrador-retriever)

However, sometimes, I want a catch all or default for one of the groups, which would be called if none of the others matched:

(defmethod get-tag-type [::dog :default] ::mutt)

However, this doesn't work unless tag is actually :default.

What is a good way to accomplish this?


Solution

  • Your dispatch function needs to know which mappings are already defined so that it can decide when to resort to a default. The methods function will return those mappings to you.

    (defmulti get-tag-type (fn [type tag] 
                             (let [mlist (methods get-tag-type)]
                               (if-let [d (get mlist [type tag])] 
                                 [type tag]
                                 [type :default]))))