Difference in Clojure writing methods
Ok, the title is not exactly what I was looking for, but it should do, I found an interesting thing about the speed of access to the write member function. I will illustrate this REPL session:
==> (defprotocol Add (add [_])) Add ==> (defrecord R [x y] Add (add [_] (+ x y))) =.R ==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (add r)))) ; Pure functional style "Elapsed time: 19.613694 msecs" nil ==> (let [r (->R 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Functional creation, but with method call "Elapsed time: 477.29611 msecs" nil ==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (.add r)))) ; Java-style "Elapsed time: 10.051506 msecs" nil ==> (let [r (R. 1 2)] (time (dotimes [_ 100000] (add r)))) ; Java-style creation with functional call "Elapsed time: 18.726801 msecs" nil
I cannot understand the reason for these differences, so I am asking this from you.
source to share
The problem with your second call is that the Clojure compiler cannot determine the type of the variable r
at compile time, so it is forced to use reflections.
To avoid this, you must add a hint type :
(let [^user.R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))
or simply
(let [^R r (->R 1 2)] (time (dotimes [_ 100000] (.add r))))
and it will be as fast as a Java style method call.
If you want to easily diagnose such problems in your code, set the parameter *warn-on-reflection*
to true:
(set! *warn-on-reflection* true)
or add it to a section :global-vars
in the file project.clj
:
:global-vars {*warn-on-reflection* true}
So, as you can see, without reflections, method calls are slightly faster than function calls. But reflections could make method calls very slow.
source to share