2

I write sometimes java methods, especially for primitives/arrays operations and I am always stuck about how to use type hints under Clojure 1.8. I saw some threads but they are (maybe ?) outdated considering they have been posted more than 2 years ago.

I will give a basic example to illustre my point (I know this example is a bit pointless). Here i want to sum two double and to return a double.

Here is a Java method :

public static double add (double a, double b) {

    return a + b;
}

Then I would like to have a Clojure wrapper :

Version 1

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add a b))

Version 2

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add ^double a ^double b))

Version 3

(defn d+ ^double 
  [^double a ^double b]
  (Doubles/add (double a) (double b)))

I do not know where to put type hints and how to put them. I have the impression that (double x) is less efficient since it is a function (maybe I am wrong ?). Then what is the difference between giving hints inside body function or outside ?

Or maybe these hints are not necessary since there is only one method in the Java class ? I do not see the logic so generally I use version 1 or 3 (more is better ?).

Note that for this example, Clojure + is always faster

3
  • 1
    *warn-on-reflection* flag would be helpful for this kind of explorations. Just set it to true, and the compiler would signal the case where it can't select needed method overload and needs a hint. Commented Mar 7, 2017 at 13:04
  • Thanks I have tested so and no hints were required at last. Do you know why this function is slower since it applies only for double ? My intuition is that the interop implies some hidden operations/costs so that Java interop is worth only when the function is costly (like a big algorithm) or when the function does not exist in Clojure. Commented Mar 7, 2017 at 13:21
  • @leetwinski Primitive type hints have nothing to do with reflection warnings, those are for objects. Primitive hints are for performance to avoid boxing. Better is to enable (set! *unchecked-math* :warn-on-boxed) at the begging of you clojure file. Commented Mar 7, 2017 at 14:06

1 Answer 1

3

Version 1 is correct. It'll emit the following byte code:

public final class compile_inspect$d_PLUS_ extends AFunction implements DDD {
    public compile_inspect$d_PLUS_() {
    }

    public static double invokeStatic(double a, double var2) {
        return Primitives.add(a, var2);
    }

    public Object invoke(Object var1, Object var2) {
        return new Double(invokeStatic(RT.uncheckedDoubleCast((Number)var1), RT.uncheckedDoubleCast((Number)var2)));
    }

    public final double invokePrim(double var1, double var3) {
        return invokeStatic(var1, var3);
    }
}

Where Primitives.add is just like your Doubles/add function.

If you want performance and avoid boxing you should set:

(set! *unchecked-math* :warn-on-boxed)

Also going through the Java interop reference (CTRL+F "primitive") will help.

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

1 Comment

Thanks a lot, I also have my answer regarding subsidiry question ==> "and numeric primitives will become Numbers unless they are immediately consumed by a method taking a primitive." which explains a bit poor isolated performance of simple operations and also some impossible taks (expanding an interface with a method returning double/float/etc.)

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.