Search code examples
clojuresignaturemethod-signaturemultimethod

Clojure: defmulti on different class types


Quick clojure question, I think this is mostly syntax related. How do I dispatch a multimethod based on specific type signatures of the arguments, for example:

(defn foo 
     ([String a String b] (println a b))
     ([Long a Long b] (println (+ a b))
     ([String a Long b] (println a (str b))))

I want to extend this to arbitrary stuff, eg two strings followed by a map, to maps followed by a double, two doubles followed by an IFn etc...


Solution

  • (defn class2 [x y]
      [(class x) (class y)])
    
    (defmulti foo class2)
    
    (defmethod foo [String String] [a b]
      (println a b))
    
    (defmethod foo [Long Long] [a b]
      (println (+ a b)))
    

    From the REPL:

    user=> (foo "bar" "baz")
    bar baz
    nil
    user=> (foo 1 2)
    3
    nil
    

    You could also consider using type instead of class; type returns :type metadata, delegating to class if there is none.

    Also, class2 does not have to be defined at top level; passing (fn [x y] ...) as the dispatch function to defmulti is fine too.