1

I would like to implement a naive non-lazy map in Java with a Java loop. My main concern is function invocation in java from Clojure.

Here is my code :

A class called NaiveClojure to implement functions using Java

package java_utils;

import java_utils.ApplyFn;

public class NaiveClojure {

    public static Object[] map (ApplyFn applyfn, Object function, Object[] coll) {

        int len = coll.length;

        for (int i = 0 ; i < len ; i++) {
            coll[i] = applyfn.apply(function, coll[i]);
        }

        return coll;
    }
}

An abstract class called ApplyFn

package java_utils;

public abstract class ApplyFn {

  public abstract Object apply (Object function, Object value);

}

So in Clojure I have

(defn java-map [f coll]
  (let [java-fn (proxy [ApplyFn] []
                  (apply [f x]
                         (f x)))]
    (seq (NaiveClojure/map java-fn f (to-array coll)))))

I tried

(doall (map inc (range 0 10000))) ;; 3.4 seconds for 10000 operations
(java-map inc (range 0 10000) ;; 5.4 seconds

My point is not to outperform map (I implemented it as an example), I just want to do things like that with specific functions (not to reinvent the wheel of Clojure).

Is there a better way to pass functions like that ? (as an easy and faster way) And to improve my coding in general (I have a poor theoritical knowledge), do you know what is killing perf here ? I would say general typing like Object but I do not see anything else

Thanks

4
  • This is not a reliable way to make performance measurements (check out criterium), and a less than x2 slowdown is hardly 'killing perf'. The sole fact that you're wrapping Clojure functions could explain why it's slower (since you're doing more work). Commented Oct 7, 2016 at 9:42
  • Oh thanks for the library name, it appears in fact that my function is faster than clojure map on sequences with both time and criterium bench. I just wondered if using IFn or a better approach would produce better results Commented Oct 7, 2016 at 10:01
  • If it's faster it's probably because you're updating an array in-place (which is not the same semantics as clojure.core/map !) Commented Oct 7, 2016 at 10:14
  • Yes of course, my point is to use this to achieve "precision" local work that does not need the flexibility and capabilities of Clojure map Commented Oct 10, 2016 at 12:54

1 Answer 1

1

You have no cause for concern here, the way you are doing it is fine and efficient.

coll[i] = applyfn.apply(function, coll[i]);

This is a very normal way to go about this. When measuring it do please, as Valentin Waeselynck points out, remember to use a reliable microbenchmarking function and also keep in mind that benchmarking this kind of small code chunk in isolation is tricky.

When you generate a clojure function it produces a "normal" java class, with a method called apply. This will not be any slower to call because you are calling a function that was originally written in Clojure than it would be to call a method on a class that was written in the normal Java syntax. Once the Hotspot JIT finishes warming it up and inlining, it will likely be as fast as it would be without the method call (which is why benchmarking this kind of thing is harder than it intuitively should be).

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks for the answer, it was the first time I was doing a thing like this. I will probably try to write methods for primitives to improve speed on specific data

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.