Using resolve to call function - Clojure - clojure

I am using resolve to call a function given they name (String), like
(call "+" 10 10 10) ;; 30
The call function:
(defn call [this & that]
(apply (resolve (symbol this)) that))
Everything works fine on REPL. But when I start the project as a server using httpkit http server, I receive a NPE.
java.lang.NullPointerException
at clojure.core$apply.invoke(core.clj:626)
at tapahtuma.http_resources$call.doInvoke(http_resources.clj:41)
at clojure.lang.RestFn.invoke(RestFn.java:423)
at tapahtuma.http_resources$forwarder.invoke(http_resources.clj:61)
at tapahtuma.http_resources$create_event.invoke(http_resources.clj:69)
at compojure.response$eval1563$fn__1564.invoke(response.clj:26)
at compojure.response$eval1524$fn__1525$G__1515__1532.invoke(response.clj:10)
at compojure.core$make_route$fn__1699.invoke(core.clj:93)
at compojure.core$if_route$fn__1683.invoke(core.clj:39)
at compojure.core$if_method$fn__1676.invoke(core.clj:24)
at compojure.core$routing$fn__1705.invoke(core.clj:106)
at clojure.core$some.invoke(core.clj:2528)
at compojure.core$routing.doInvoke(core.clj:106)
at clojure.lang.RestFn.applyTo(RestFn.java:139)
at clojure.core$apply.invoke(core.clj:628)
at compojure.core$routes$fn__1709.invoke(core.clj:111)
at tapahtuma.http_resources$wrap_content_type$fn__7192.invoke(http_resources.clj:22)
at ring.middleware.cors$wrap_cors$fn__1800.invoke(cors.clj:47)
at org.httpkit.server.HttpHandler.run(RingHandler.java:33)
at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
at java.lang.Thread.run(Thread.java:745)
At line 41 of http_resources I have the call function.
I don't figured out what are happen here. Thanks for any help here. I created a project to help reproduce the problem

The following modification to your reproducer -- fully qualifying the namespace -- works properly:
(defn call [this & that]
(let [this-sym (symbol this)
this-resolved (ns-resolve 'resolver-clj.core this-sym)]
(.println System/out (str "current-ns: " *ns*))
(.println System/out (str "this-sym: " this-sym))
(.println System/out (str "this-resolved: " this-resolved))
(apply this-resolved that)))
The reason is obvious when you look at the value of *ns* in the reproduction environment, which is clojure.core.

Related

Clojure function will not compile

Please excuse my complete lack of knowledge, but why doesn't this function compile?
(defn add-onehundred
[num]
(+ num 100))
(add-onehundred 5)
I get this error thrown in the terminal:
Exception in thread "main" Syntax error compiling at (/private/var/folders/ls/j5fjkkb96mx340pb_gm12t740000gn/T/form-init13922061526950471210.clj:1:126).
at clojure.lang.Compiler.load(Compiler.java:7647)
at clojure.lang.Compiler.loadFile(Compiler.java:7573)
at clojure.main$load_script.invokeStatic(main.clj:452)
at clojure.main$init_opt.invokeStatic(main.clj:454)
at clojure.main$init_opt.invoke(main.clj:454)
at clojure.main$initialize.invokeStatic(main.clj:485)
at clojure.main$null_opt.invokeStatic(main.clj:519)
at clojure.main$null_opt.invoke(main.clj:516)
at clojure.main$main.invokeStatic(main.clj:598)
at clojure.main$main.doInvoke(main.clj:561)
at clojure.lang.RestFn.applyTo(RestFn.java:137)
at clojure.lang.Var.applyTo(Var.java:705)
at clojure.main.main(main.java:37)
Caused by: java.lang.Exception: Cannot find anything to run for: clojure-noob.core
at user$eval140.invokeStatic(form-init13922061526950471210.clj:1)
at user$eval140.invoke(form-init13922061526950471210.clj:1)
at clojure.lang.Compiler.eval(Compiler.java:7176)
at clojure.lang.Compiler.eval(Compiler.java:7166)
at clojure.lang.Compiler.load(Compiler.java:7635)
... 12 more
full code as in the editor here, when main is commented out it will not compile, when it isn't commented out add-onehundred returns nothing:
(ns clojure-noob.core
(:gen-class))
; (defn -main
; "I don't do a whole lot ... yet."
; [& args]
; (println "Hello, Mate"))
(defn add-onehundred
[num]
(+ num 100))
(add-onehundred 5)
Based on the error message, you're trying to run this with:
lein run
and you have the following in your project.clj file:
:main clojure-noob.core
or:
:main ^:skip-aot clojure-noob.core
This tell Leiningen to look for a -main function in the clojure-noob.core namespace in order to "run" your new application -- but you've commented it out, so Leiningen cannot find it, hence "Cannot find anything to run for: clojure-noob.core".
Uncomment your -main and have it call add-onehundredand print the result. Note that functions in Clojure must be defined (or at least declared) before they are used, so your code will end up looking like this:
(ns clojure-noob.core
(:gen-class))
(defn add-onehundred
[num]
(+ num 100))
(defn -main
"I don't do a whole lot ... yet."
[& args]
(println (add-onehundred 5)))
lein run should run your app and print 105.

Get 'Attempting to call unbound fn' in clojure command line app

I have the following code and it works when I go through and step through it in Cider, but when I run it straight through on the command line I get the following error:
Exception in thread "main" java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure-todo.todo/execute-todo-cmd, compiling:(/private/var/folders/d_/b8gmsvl16sgdg70m15gx20l40000gn/T/form-init6080372317525706515.clj:1:125)
at clojure.lang.Compiler.load(Compiler.java:7391)
at clojure.lang.Compiler.loadFile(Compiler.java:7317)
at clojure.main$load_script.invokeStatic(main.clj:275)
at clojure.main$init_opt.invokeStatic(main.clj:277)
at clojure.main$init_opt.invoke(main.clj:277)
at clojure.main$initialize.invokeStatic(main.clj:308)
at clojure.main$null_opt.invokeStatic(main.clj:342)
at clojure.main$null_opt.invoke(main.clj:339)
at clojure.main$main.invokeStatic(main.clj:421)
at clojure.main$main.doInvoke(main.clj:384)
at clojure.lang.RestFn.invoke(RestFn.java:421)
at clojure.lang.Var.invoke(Var.java:383)
at clojure.lang.AFn.applyToHelper(AFn.java:156)
at clojure.lang.Var.applyTo(Var.java:700)
at clojure.main.main(main.java:37)
Caused by: java.lang.IllegalStateException: Attempting to call unbound fn: #'clojure-todo.todo/execute-todo-cmd
Here is the code. I guess it's a namespace error, but I'm confused as to how it could be a namespace issue if it's working in cider.
(ns clojure-todo.todo
(:gen-class))
///// Other Code here
(defn print-msg-list [list]
(doseq [item list] (print-msg item)))
(defn create-todo [todo-string] (hash-map :todo-content todo-string :checked false))
(defn list-todos [todos]
(doseq [single-todo todos]
(do
(print (get single-todo :todo-content))
(let [is-checked (get single-todo :checked)]
(if is-checked
(print-msg :is-checked)
(print-msg :is-unchecked))))))
(defn add-todo []
(do
(print-msg :add-todo-message)
(let [todo-string (read-line) the-todo-created (create-todo todo-string)]
(def the-todos (conj the-todos the-todo-created))
(list-todos the-todos)))
(def todo-fns {"1" add-todo "2" delete-todo "3" list-todos "4" check-todo})
(defn execute-todo-cmd [command]
(get todo-fns command nil)))
(defn take-todo-command [backup-fn]
(let [command (read-line)]
(if (= command "q")
(print-msg :goodbye)
(let [todo-fn (execute-todo-cmd command)]
(if todo-fn
(todo-fn)
(do
(print-msg :sorry)
(print-msg :border)
(backup-fn)))))))
(defn run-app []
(do
(print-msg :welcome)
(print-msg-list '(:add-todo :list-todos :delete-todo :check-todo :quit))
;; The take-todo-command fn takes a backup in case the user types in
;; a command that's not supported by the application. In this case we just
;; want the app to restart
(take-todo-command run-app)))
This was just missing a close paren in add-todo, and there is an extra close paren in execute-todo-cmd. So execute-todo-cmd does not exist until add-todo is run, which is why it yields an unbound-fn error.

Clojure - call one method from another, both methods are in the same protocol/record

A protocol has two methods:
(defprotocol ITimeInterop
(parse-int [this str])
(stringify-time [this host-time]))
Here I am calling parse-int from stringify-time:
(defrecord CljTime []
ITimeInterop
(parse-int [_ str]
(Integer. (re-find #"[0-9]*" str)))
(stringify-time [the-obj host-time]
(let [specific-format (SimpleDateFormat. "MM dd yyyy HH:mm:ss")
as-str (.format specific-format host-time)
[month day-of-month year time-str] (str/split as-str #" ")
month-as-idx (dec (parse-int the-obj month))]
{})))
The error message I am getting is 'java.lang.RuntimeException: Unable to resolve symbol: parse-int in this context'.
How should I be calling parse-int from stringify-time?
Perhaps using a dot in front of parse-int would help?
Answer Unfortunately I did not show namespaces in the question. Using a dot seemed to work but a better resolution was to :require the protocol's namespace :as i then call using: (i/parse-int the-obj month).
There should be no problem calling parse-int in stringify-time as long as you provide with the this as the first argument, which is exactly what you have done. But in your presented code, I expect the error message to be "unable to resolve month".
I'd suggest you double check your question first.

Clojure Agent Parellel HTTP IllegalStateException and await-for

I am working through the example of making parallel http requests in Clojure,
http://lethain.com/a-couple-of-clojure-agent-examples/
In particular
(ns parallel-fetch
(:import [java.io InputStream InputStreamReader BufferedReader]
[java.net URL HttpURLConnection]))
(defn get-url [url]
(let [conn (.openConnection (URL. url))]
(.setRequestMethod conn "GET")
(.connect conn)
(with-open [stream (BufferedReader.
(InputStreamReader. (.getInputStream conn)))]
(.toString (reduce #(.append %1 %2)
(StringBuffer.) (line-seq stream))))))
(defn get-urls [urls]
(let [agents (doall (map #(agent %) urls))]
(doseq [agent agents] (send-off agent get-url))
(apply await-for 5000 agents)
(doall (map #(deref %) agents))))
(prn (get-urls '("http://lethain.com" "http://willarson.com")))
When I run this in the
IllegalStateException await-for in transaction
What does this mean and how do I fix it?
Taking the comment on the question into account:
A transaction is being set up in the process of loading your namespace, and since it has a call to get-urls at the top-level, the await-for happens in that transaction and throws the exception.
The best way to fix that is to put the prn / get-urls form inside a function and only call it once the namespace is loaded. (If you wanted to run this code as a standalone app, with lein run or java -jar on an überjar, you'd put a call to that function inside -main.)
Incidentally, the transaction is set up when you use :reload-all, but not without it. (See the private functions load-lib, which checks for the presence of :reload-all and decides to use the private function load-all if it's there, and load-all itself, which is where the transaction is set up. Here's a link to the 1.5.1 source.)

Clojure gives 'wrong number of args' yet the arg is there on the previous line [duplicate]

This question already has an answer here:
Closed 10 years ago.
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?
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