MRK187
MRK187

Reputation: 1595

clojure code giving error: java.lang.Integer cannot be cast to clojure.lang.IFn

Hi I have this school project that I am almost done with so I don't need help with the code, problem is I've never coded in clojure but for this assignment had to do a try and catch macro in clojure with bound forms, there are some REPL commands that are expected to give different responses for the assignment to pass,,

Anyways Im getting an error that I've been googling but nothing is specific to this problem and most explanations basically need there own explanation nothing seems to be beginner adapted so it doesnt do much for me.

(defmacro safe [bindings & code]
(if (list? bindings)
`(try 
   ~bindings 
  (catch Throwable except# except#)) 

(if (= (count bindings) 0)
  `(try ~code 
     (catch Throwable except# except#)) 

  `(let ~(subvec bindings 0 2)

     (try
       (safe ~(subvec bindings 2) ~@code)
       (catch Throwable except# except#) 

       (finally
         (. ~(bindings 0) close))))))) ;;safe



(def divider(safe (/ 1 0)))
(def reader (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))

So the error Im getting is

=> (def v (safe [s (FileReader. (java.io.File. "C:/text.txt"))] (. s read)))
#'myProject.core/v
=> v
#<ClassCastException java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn>

So kindly anyone that knows clojure please give me some hints on what is wrong, all the hints Im getting is that there should be a paranthesis missplaced, I've checked the code over and over but cant find any misstypes etc. Thank you !

Upvotes: 1

Views: 1461

Answers (3)

MRK187
MRK187

Reputation: 1595

Solved!

Missing unquote slicing in the third try block, causing exception

java.lang.ClassCastException: java.lang.Integer cannot be cast to clojure.lang.IFn

this was caused due to extra paranthesis when reading s recursivly,

macroexpand ex.

(pprint (macroexpand-all form)) 
 (let*[s
  (new FileReader 
   (new File "test.txt"))]
    (try
     (try
       ((.s read)) ;<= here

Had to change the third try/catch from

(try
   (safe ~(subvec bindings 2) ~@code)

to:

(try
   (safe ~@(subvec bindings 2) ~@code)

To my understanding the problem was that I was returned a list with a paranthesis like (1(2 3)) causing exception when read, unquoting makes it look (1 2 3) and can be read or (in this case) casted from java to clojure.

reservations for misspellz or calling shit the wrong name! :)

Many thanks to A.Webb and patz.

Upvotes: 0

patz
patz

Reputation: 797

 (FileReader. (java.io.File. "/tmp/text.txt"))

is giving you the value of the first character on the file

cat /tmp/text.txt => abcd

(let [s (FileReader. (java.io.File. "/tmp/text.txt"))] (. s read)) => 97

same as

(int \a)

and your macro expect a function. try:

(safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] #(+ 6)) or (safe [s (FileReader. (java.io.File. "/tmp/text.txt"))] (fn [] (. s read)

Upvotes: 0

A. Webb
A. Webb

Reputation: 26446

Use macroexpand and friends to help debug

(def form (quote (safe [s (FileReader. (java.io.File. "test.txt"))] (. s read))))

(pprint (macroexpand form)) ;=>
(let*
 [s (FileReader. (java.io.File. "test.txt"))]
 (try
  (user/safe [] (. s read))  ; <--- Macro is recursive
  (catch java.lang.Throwable except__1104__auto__ except__1104__auto__)
  (finally (. s user/close))))

Macro is recursive, so this is not the full expansion

(pprint (clojure.walk/macroexpand-all form)) ;=>
(let*
 [s (new FileReader (new java.io.File "test.txt"))]
 (try
  (try
   ((. s read)) ; <-- Too many parenthesis! 
   (catch ...

The read call returns an integer, which is in turn being called as a function in the recursive macro expansion.

Upvotes: 5

Related Questions