Reputation: 1144
Is it possible to declare a variadic function in Clojure that can be called as a varargs method from Java?
Consider this extract from some code under development:
(ns com.mydomain.expression.base
(:gen-class
:name com.mydomain.expression.Base
:methods [^:static [exprFactory [String String ?????] Object]]
)
(defn expr-factory
; worker function that is also called from Clojure
[id func & args]
(let [ex ("construction code here")]
ex))
(defn -exprFactory
; interface method called from Java
[idStr funcStr & argsArray]
(apply expr-factory idStr funcStr (seq argsArray)))
Is there anything I can put in place of ?????
to allow Java to call the exprFactory
method and to know that it is a varargs method:
import com.mydomain.expression.Base;
...
Object e1 = Base.exprFactory("e1", "day");
Object e2 = Base.exprFactory("e2", "length", "string");
Object e3 = Base.exprFactory("e3", "*", 4, 5);
Object sum = Base.exprFactory("sum", "+", e1, e2, e3);
To make this a little clearer, I know I use Object
in place of ?????
and change exprFactory
to:
(defn -exprFactory
; interface method called from Java
[idStr funcStr argsArray]
(apply expr-factory idStr funcStr (seq argsArray)))
..but that means I have to write Java calls like this:
import com.mydomain.expression.Base;
...
Object e1 = Base.exprFactory("e1", "day", new Object[0] ));
Object e2 = Base.exprFactory("e2", "length", new Object[] { "string" }));
Object e3 = Base.exprFactory("e3", "*", new Integer[] { 4, 5 }));
Object sum = Base.exprFactory("sum", "+", new Object[] { e1, e2, e3 }));
Again, I know I could write a varargs wrapper method in Java that calls the non-variadic exprFactory
, but I'd like to avoid that if possible.
Upvotes: 11
Views: 867
Reputation: 106351
I would suggest writing your helper function on the Java side, something like the "applyToHelper" in clojure.lang.AFn
This would take the form of a Java function that looks something like:
public Object invokeVariadic(IFn function, Object... args) {
switch (args.length) {
case 0:
return function.invoke();
case 1:
return function.invoke(args[0]);
/// 20-odd more cases
}
}
It's a bit of a hack and depends on the internal definition of clojure.lang.IFn, but at least you will get relatively nice variadic syntax on the Java side (i.e. no need to do the new Object[] {...}
stuff).
Upvotes: 1