Search code examples
clojurejava.util.concurrent

Getting result of a Future after submitting function to java.util.concurrent.ExecutorService


The following works. The result is "hello world"

  (def ^Callable f (fn [] "hello world"))
  (let [e (java.util.concurrent.Executors/newSingleThreadExecutor)]
    (try
      (.get (.submit e f))
      (finally (.shutdown e))))

But the following doesn't. The result of get is nil

(def e (java.util.concurrent.Executors/newSingleThreadExecutor))
(.get (.submit e f))

Why? I checked that f is getting called by replacing it with something that has a side effect. The only difference I can see is that e is bound using let in one and def in the other.

Another question. If I don't have the ^Callable typehint for f the first example quietly returns nil. Shouldn't it throw an exception "more than one matching method found" for the submit call since f is both Runnable and Callable? If I define f using let like the following then the exception is thrown

(let [e (java.util.concurrent.Executors/newSingleThreadExecutor)]
  (let [f (fn [] "hello world2")]
    (try
      (.get (.submit e f))
      (finally (.shutdown e)))))

Thanks


Solution

  • The problem was the type of e could not be inferred in

    (def e (java.util.concurrent.Executors/newSingleThreadExecutor))
    

    when I change this to

    (def ^java.util.concurrent.ExecutorService e (java.util.concurrent.Executors/newSingleThreadExecutor))
    

    then (.get (.submit e f)) gives proper answer "hello world". Somehow clojure is inferring the correct type when e is defined using a let and thus does not require a similar type hint.

    setting *warn-on-reflection* to true helped to debug this.