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.
Core Java bootcamp program with Hands on practiceMethods which uses variable arguments (varargs, arguments with three dots) are known as variadic functions.
Functions Returning Functions and Closures Our first function will be called adder . It will take a number, x , as its only argument and return a function. The function returned by adder will also take a single number, a , as its argument and return x + a . The returned function form adder is a closure.
*type* indicates the data type the *va_list ap* should expect (double, float, int etc.) This makes a copy of the variadic function arguments. This ends the traversal of the variadic function arguments. Here, va_list holds the information needed by va_start, va_arg, va_end, and va_copy.
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).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With