Can I try and catch in different (but nested) macros?

try is in one macro, and catch is in the second, which is called first. How to make the following work?

 (defmacro catch-me [] `(catch ~'Exception ~'ex true)) (defmacro try-me [] `(try (+ 4 3) (catch-me))) 

The try-me extension looks good:

 (clojure.walk/macroexpand-all '(try-me)) 

gives

 (try (clojure.core/+ 4 3) (catch Exception ex true)) 

but a call (try-me) gives:

 "Unable to resolve symbol: catch in this context", 

which, BTW, is also the message you will receive in the REPL when using catch, if not in an attempt.

UPDATE:

Here is how I can make it work (thanks, @Barmar), here you can see the actual context of my code:

 (defmacro try-me [& body] `(try ~@body ~@ (for [[e msg] [[com.mongodb.MongoException$Network "Database unreachable."] [com.mongodb.MongoException "Database problem."] [Exception "Unknown error."]]] `(catch ~e ~'ex (common/site-layout [:div {:id "errormessage"} [:p ~msg] [:p "Error is: " ~e] [:p "Message is " ~'ex]]))))) 

but this is what I was hoping for (using a separate catch-me macro):

 (defmacro try-me [& body] `(try ~@body (catch-me com.mongodb.MongoException$Network "Database unreachable.") (catch-me com.mongodb.MongoException "Database problem.") (catch-me Exception "Unknown error."))) 

I think it would be easier to write / support.

Any ideas? I need a citation syntax because I pass the parameters, so unfortunately Arthur's answer cannot be applied (or can it somehow?), But I did not publish my actual context just now.

+6
source share
2 answers

The reason you get this error is because the syntax for try :

 (try expr* catch-clause* finally-clause?) 

This means that there can be any number of expressions before catch and finally clauses. try scans expr until it finds one that starts with catch or finally . He does this before expanding any macros, as he is simply trying to figure out where the exprs and catch / finally expressions begin. It collects all catch and finally sentences and sets up an appropriate error handling environment for them.

Once he does this, he usually executes all forms of expr . Thus, it expands its macros and then executes them. But catch not a function or a special form, it is just what try looking for at an earlier stage. Therefore, when it runs normally, you get the same error as when you type it in the REPL.

What you should probably do is write a macro that you clear around all of your code, which expands in the try / catch expression that you want. Without an example of what you are trying to accomplish, it is difficult to give a concrete answer.

+5
source

The short answer is YES, although nested macros with special shapes can lead to some double collimation headaches like this. Characters must not be evaluated at both levels of expansion:

 user> (defmacro catch-me [] '(list 'catch 'Exception 'ex 'true)) user> (defmacro try-me [] `(try (+ 4 3) ~(catch-me))) #'user/try-me user> (try-me) 7 

and to see that it also gets an exception:

 user> (defmacro try-me [] `(try (/ 4 0) ~(catch-me))) #'user/try-me user> (try-me) true 
+1
source

All Articles