2

In Clojure, the branch of an if expression that doesn't match the condition is not evaluated, so no exception is thrown in evaluating the below expression:

=> (if nil (/ 1 0))
nil

However, macros will still be expanded before evaluating the if, so you can still get exceptions like so:

=> (if nil (proxy [nil] []))
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1)

I'm writing a macro for which the name of an interface will sometimes be provided as an arg, in which case the macro will generate the code for a call to proxy. Other times, the interface arg will be nil, and then the macro expands to something like (if nil (proxy [nil] []), so I get the above exception. An SSCE would be:

=> (defmacro make-listener [listener-name & methods]
     `(if ~listener-name
        (proxy [~listener-name] []
          ~@(map (fn [m] `(~m [e#])) methods))))
#'user/make-listener
=> (make-listener java.awt.event.ActionListener actionPerformed)
#<Object$ActionListener$46793e3a user.proxy$java.lang.Object$ActionListener$46793e3a@ed5b2>
=> (make-listener nil)
CompilerException java.lang.NullPointerException, compiling:(NO_SOURCE_PATH:1) 

How can I write the macro in a way that doesn't throw an exception when no interface arg is provided?

om-nom-nom
  • 62,329
  • 13
  • 183
  • 228
OpenSauce
  • 8,533
  • 1
  • 24
  • 29

1 Answers1

4

If listener-name is nil then the macro should do nothing i.e you need to check for listener-name at macro expansion (not in the code the macro emit).

(defmacro make-listener [listener-name & methods]
  (if listener-name
     `(proxy [~listener-name] []
       ~@(map (fn [m] `(~m [e#])) methods)))) 
Ankur
  • 33,367
  • 2
  • 46
  • 72
  • Ankur, I don't understand why yours works but sauce's doesn't.. shouldn't the 'if' clause in sauce's example delay the creation of the proxy in the same way yours does? – jk. Apr 04 '13 at 19:39
  • @jk: `proxy` is a macro and it throws the null exception when it is being macro-expanded by the compiler. The null exception is compile time exception not runtime exception. – Ankur Apr 05 '13 at 04:12