3
votes

I'm writing a Java class (it's a GUI widget) which will be used from Clojure. When the Java class is initialized, it must be provided a callback function. When certain conditions are met, the Java class will call the function with a single argument.

I'm trying to figure out the type which the callback function should be declared as in the Java code.

I know that Clojure functions implement Runnable and Callable, but neither Runnables nor Callables can take an argument when invoked. Of course, Clojure functions also implement IFn, but I would prefer to use a standard Java type. Any ideas?

2

2 Answers

3
votes

I checked all the interfaces implemented by Clojure functions using:

(ancestors (class (fn [a] a)))

And got the answer:

#{clojure.lang.AFunction java.lang.Object clojure.lang.Fn clojure.lang.IFn clojure.lang.IObj java.io.Serializable java.util.concurrent.Callable java.lang.Runnable java.util.Comparator clojure.lang.AFn clojure.lang.IMeta}

Drat! Looks like I won't do better than to use IFn.

It's strange to think that after almost 20 years of history, the Java platform has no standard class or interface for a lambda-like object! There are ActionListeners and this-listeners and that-listeners, Runnable and Callable, but no general purpose "function" objects.

-1
votes

I have the similar problem, then created a jar for everyone

<dependency>
    <groupId>com.incarcloud</groupId>
    <artifactId>ac-func-tion</artifactId>
    <version>1.1.0</version>
</dependency>

Then can write code like this:

import com.incarcloud.lang.*;

Action<Integer> actFoo = (x)->{ System.out.println(x); };

// you can call it directly
actFoo.run(5);
// or you can call it with a wrap
Runnable wrapFoo = new RunnableAction<>(actFoo, 5);
wrapFoo.run();
// or in a single line
(new RunnableAction<Integer>((x)->{ System.out.println(x); }, 5)).run();

There are total 10 interfaces, can accept 5 arguments at most.

Action<T>  Action2<T1,T2> ... Action5<T1,T2,T3,T4,T5> these like Runnable without return value
Func<R,T>  Func2<R,T1,T2> ...  Func5<R,T1,T2,T3,T4,T5> these like Callable with return type R

each has wrap class RunnableAction, RunnableAction2 ... CallableFunc, CallableFunc2 ...

and thread pool wrap class

Action2<Integer, Integer> action = (a, b)->{
    System.out.println(String.format("Action(%d, %d)", a, b));
};

ExecutorForAcFunction pool = new ExecutorForAcFunction(Executors.newFixedThreadPool(2));
for(int i=0;i<5;i++){
    pool.submit(action, i, 10-i);
}

More information can be found here https://github.com/InCar/ac-func-tion