This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2022-11-06
Channels
- # announcements (3)
- # babashka (1)
- # beginners (26)
- # calva (1)
- # cider (17)
- # clj-commons (16)
- # clj-kondo (11)
- # clojure (21)
- # clojure-europe (9)
- # clojure-norway (1)
- # clojure-portugal (2)
- # clojure-spec (8)
- # clojure-uk (4)
- # clojurescript (35)
- # datomic (5)
- # emacs (9)
- # figwheel-main (15)
- # fulcro (26)
- # honeysql (1)
- # lsp (5)
- # off-topic (2)
- # polylith (1)
- # rdf (6)
- # re-frame (4)
- # reagent (15)
- # reitit (9)
- # releases (2)
- # shadow-cljs (4)
- # sql (25)
- # squint (2)
- # xtdb (7)
I am receiving More than one matching method found: submit
when trying to use an ExecutorService
. It looks like there are multiple versions of submit
, two that accept Runnable
and one for Callable
, so I tried (I think superfluously) to type hint the passed fn, but since IFn
already implements both of those, I didn't think it would work, and indeed it did not. What probably obvious thing am I missing?
What code do you have exactly?
user=> (def pool (java.util.concurrent.Executors/newFixedThreadPool 1))
#'user/pool
user=> (.submit pool (fn []))
#object[java.util.concurrent.FutureTask 0x13047d7d "java.util.concurrent.FutureTask@13047d7d[Completed normally]"]
user=>
This is dummy code I wrote in an effort to break the problem down but same issue
(let [ex (Executors/newFixedThreadPool 3)]
(dotimes [n 3] (doto
ex
(.submit #(println (str "on thread no. " n))) .get)))
check=> (let [e (Executors/newFixedThreadPool)]
(.submit e (fn [] (println "HI!"))))
Syntax error (IllegalArgumentException) compiling . at (REPL:60:9).
No matching method newFixedThreadPool found taking 0 args for class java.util.concurrent.Executors
both runnable and callable are fine, depending on your needs
check=> (let [e (Executors/newFixedThreadPool 1)]
@(.submit e ^Callable (fn [] 3)))
3
check=> (let [e (Executors/newFixedThreadPool 1)]
(.submit e ^Runnable (fn [] (println "HI!"))))
#object[java.util.concurrent.FutureTask 0x14d5b143 "java.util.concurrent.FutureTask@14d5b143[Not completed, task = java.util.concurrent.Executors$RunnableAdapter@3112ad10[Wrapped task = check$eval9019$fn__9020@49452b11]]"]
Aha, I think I see where I went astray...I had the ^Callable
hint in the body of my function like (fn ^Callable [] ...)
which in hindsight makes little sense
@U2FRKM4TW if you (def ^:const pool ...)
then it doesn't work again
EDIT: but for an unrelated reason actually. Instead try
(def ^java.util.concurrent.ThreadPoolExecutor ex (java.util.concurrent.Executors/newFixedThreadPool 1))
(.submit ex (fn []))
to see that when the compiler knows the target of the host expression, it will reflect at compile-time and throw error if it finds several matching methods.@U2FRKM4TW what's your jvm version?
I think it has something to do with that the compiler knows the type of pool
and let-locals, so when it tries to resolve the instance method it sees that there are two competing signatures
But when it sees (.submit pool (fn []))
without knowing the class of pool
(ie. when deffing without the ^:const
)it can't reflect and see the signatures of submit
@U11BV7MTK OpenJDK 11.0.16 on Ubuntu.
So to completely get rid of reflection you need to hint both the executor and then let bind the fn and type hint the name, or do something like ^Callable (identity (fn [] ...))
> you cannot type hint a function literal But there's no reflection warnings on this, with type hinting on the function literal?
(.submit (java.util.concurrent.Executors/newFixedThreadPool 1) ^Callable (fn [] 1))
@U0NCTKEV8 could that be in a core.async context rather than just Clojure at large?
I guess? Seems unlikely because with core.async you don't directly use executors. I just could have sworn I remembered that from fighting with type hinting executors in the past. There have been other issues in the past where reflection would non-deterministicly choose which overload it used