Creating a Runnable from a Clojure fn

726 views
Skip to first unread message

Stuart Sierra

unread,
Mar 6, 2008, 4:37:52 PM3/6/08
to Clojure
Hello all,
Given that Clojure fns are Callable but not Runnable, i.e.:

user=> (instance? java.util.concurrent.Callable (fn []))
true
user=> (instance? java.lang.Runnable (fn []))
false

Is there an efficient way to use a Clojure fn as a Runnable? I need a
Runnable so I can use
ScheduledExecutorService.scheduleWithFixedDelay(). The best I could
come up with is:

(proxy [Runnable] [] (run [] (my-function... )))

But I feel like a proxy shouldn't be necessary.

I assume fn's cannot implement both Callable and Runnable, because a
lot of Executor methods are overloaded for both.

Thanks,
-Stuart

Rich Hickey

unread,
Mar 6, 2008, 4:52:24 PM3/6/08
to Clojure


On Mar 6, 4:37 pm, Stuart Sierra <the.stuart.sie...@gmail.com> wrote:
> Hello all,
> Given that Clojure fns are Callable but not Runnable, i.e.:
>
> user=> (instance? java.util.concurrent.Callable (fn []))
> true
> user=> (instance? java.lang.Runnable (fn []))
> false
>
> Is there an efficient way to use a Clojure fn as a Runnable? I need a
> Runnable so I can use
> ScheduledExecutorService.scheduleWithFixedDelay(). The best I could
> come up with is:
>
> (proxy [Runnable] [] (run [] (my-function... )))
>
> But I feel like a proxy shouldn't be necessary.
>

There's nothing wrong/inefficient with a proxy - it's much like using
an anonymous class to implement Runnable in Java, except the proxy
class will be created only once, cached, and reused. You shouldn't
hesitate at all to do this - might be a candidate for a library
function/macro.

> I assume fn's cannot implement both Callable and Runnable, because a
> lot of Executor methods are overloaded for both.
>

Right, it can be awkward to implement both overloading-wise, so I
chose to implement the more recent solution.

Rich

timmy

unread,
Mar 7, 2008, 4:23:27 AM3/7/08
to Clojure


On 6 Mrz., 22:37, Stuart Sierra <the.stuart.sie...@gmail.com> wrote:
> (proxy [Runnable] [] (run [] (my-function... )))

i did it exactly this way, using a runnable function with
scheduleAtFixedRate. It worked fine. I used it to update a canvas
asynchronously 25 times a second.

erik

Rich Hickey

unread,
Mar 7, 2008, 7:35:48 AM3/7/08
to Clojure
:)

Yes, they are much faster than needed to do that!

(def #^Runnable r (proxy [Runnable] [] (run [] (rand))))

(time (dotimes x 1000000 (. r (run))))
"Elapsed time: 203.78 msecs"


Rich

Stuart Sierra

unread,
Mar 7, 2008, 6:17:41 PM3/7/08
to Clojure
On Mar 7, 7:35 am, Rich Hickey <richhic...@gmail.com> wrote:
> On Mar 7, 4:23 am, timmy <i_am_wea...@kittymail.com> wrote:
>
> > On 6 Mrz., 22:37, Stuart Sierra <the.stuart.sie...@gmail.com> wrote:
>
> > > (proxy [Runnable] [] (run [] (my-function... )))
>
> > i did it exactly this way, using a runnable function with
> > scheduleAtFixedRate. It worked fine. I used it to update a canvas
> > asynchronously 25 times a second.
>
> :)
>
> Yes, they are much faster than needed to do that!

Got it; thanks all.
-Stuart
Reply all
Reply to author
Forward
0 new messages