1

Possible Duplicate:
Clojure error on thread: java.lang.IllegalArgumentException: Key must be integer

This code is so simple, I am confused how it could go wrong. I have:

(defn create-server [port]
  (let [ss (new ServerSocket port)]
    (start-thread (fn [ss]
                    (while (not (. ss (isClosed)))
                      (try (listen-and-respond ss)
                          (catch SocketException e))))))) 

(defn -main [& args]
  (println "Server is starting")
  (let [port (Integer/parseInt (first args))]
    (println "port: " port)
    (create-server port)))

I compile this, then uberjar it, then start it on the command line. These lines:

(println "Server is starting")

(println "port: " port)

prints out:

Server is starting port: 3457

On the next line, create-server is called and I get this error:

Exception in thread "Thread-1" clojure.lang.ArityException: Wrong number of args (0) passed to:     core$create-server$fn
    at clojure.lang.AFn.throwArity(AFn.java:437)
    at clojure.lang.AFn.invoke(AFn.java:35)
    at clojure.lang.AFn.run(AFn.java:24)
    at java.lang.Thread.run(Thread.java:680)

Clearly, the line in -main can not be a problem, because I know that "port" has a value of 3457 the line before the first call to create-server. I also notice this error is in Thread-1, so I am thinking that somehow this code recurs in a way that I don't understand.

Any thoughts?

Community
  • 1
  • 1
cerhovice
  • 676
  • 1
  • 10
  • 24
  • 2
    Please attempt to indent your code when posting questions -- especially in Clojure, this is pretty much essential for readability. Any appropriate editor should do the job well. – Charles Duffy Sep 03 '12 at 00:44

1 Answers1

3

If start-thread ultimately calls into new Thread(Runnable) then the error is actually because public void run() of Runnable does not have any arguments.

Because ss is declared in the enclosing let expression, it will be visible to your anonymous function you passed to start-thread.

Edit Reproducing your exact problem at the REPL using Java interop (*1 in the REPL means "the value returned from the previous evaluation):

user=> (doto (new Thread (fn run [s] (println "blah"))))
#<Thread Thread[Thread-14,5,main]>
user=> (.start *1)
Exception in thread "Thread-14" nil
clojure.lang.ArityException: Wrong number of args (0) passed to: user$eval318$run
at clojure.lang.AFn.throwArity(AFn.java:437)
at clojure.lang.AFn.invoke(AFn.java:35)
at clojure.lang.AFn.run(AFn.java:24)
at java.lang.Thread.run(Thread.java:679)


user=> (doto (new Thread (fn run [] (println "blah"))))
#<Thread Thread[Thread-15,5,main]>
user=> (.start *1)
nilblah
noahlz
  • 10,202
  • 7
  • 56
  • 75
  • 3
    In other words, changing *`(start-thread (fn [ss]`* to *`(start-thread (fn []`* should fix the problem. Since the `fn` definition will close over the `ss` value declared in the surrounding `let` you really don't want to declare another binding with the same name as an argument to the anonymous function for your thread. – DaoWen Sep 03 '12 at 00:40