Search code examples
performanceclojuremultimethod

Are clojure multimethods slow by nature


I was looking at the clojure.core function re-groups:

(defn re-groups [^java.util.regex.Matcher m]
    (let [gc  (. m (groupCount))]
      (if (zero? gc)
        (. m (group))
        (loop [ret [] c 0]
          (if (<= c gc)
            (recur (conj ret (. m (group c))) (inc c))
             ret))))) 

And thought that it would be "better" to rewrite it as a multimethod:

(defmulti re-groups (fn [^java.util.regex.Matcher m] (.groupCount m)))
(defmethod re-groups 0 [m] (.group m))
(defmethod re-groups :default [m]
        (let [idxs (range (inc (.groupCount m)))]
             (reduce #(conj %1 (.group m %2)) [] idxs))) 

Yet when comparing the times I was surpised to see the rewrite is 4 times slower:

clojure.core: "Elapsed time: 668.029589 msecs"
multi-method: "Elapsed time: 2632.672379 msecs" 

Is this a natural result of multimethods or is there something else wrong here?


Solution

  • Clojure multimethods allow runtime polymorphic behavior based on arbitrary dispatch functions. This is very powerful for building ad-hoc hierarchies and abstractions, but you pay a performance hit for such flexibility. You may wish to re-implement your solution with a protocol. Only use multimethods when you need complete runtime type flexibility.