OpenSauce
OpenSauce

Reputation: 8633

Prevent macro expansion in false branch of if expression

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?

Upvotes: 2

Views: 219

Answers (1)

Ankur
Ankur

Reputation: 33657

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)))) 

Upvotes: 4

Related Questions