I have a macro that will implement a Java interface that is a listener. I defined the macro to take a map containing functions that I want to destructure, and use for each of the interfaces methods. This is the macro :-
(defmacro with-cache-listener-m [component event body]
(let [{:keys [f-insert f-update]} body]
`(. ~component addMapListener
(proxy [AbstractMapListener] []
(entryInserted [~event] ~f-insert ~event)
(entryUpdated [~event] ~f-update ~event)))))
The body map is this :-
(def m-callbacks {:f-insert callback-insert :f-update callback-update})
But when I call (macroexpand '(with-cache-listener-m test-cache e m-callbacks))
it expands to (. test-cache user/addMapListener (clojure.core/proxy [com.tangosol.util.AbstractMapListener] [] (user/entryInserted [e] nil e) (user/entryUpdated [e] nil e)))
The callback functions are nil. Do I need to define them differently or am I going about this the wrong way.
When you call the with-cache-listener-m
macro, the body
argument get bounded to 'm-callbacks
as a symbol, so when you try to destructure that local var it won't work because it ain't a map. You can let the resulting form do the job like this:
(defmacro with-cache-listener-m [component event body]
`(let [{:keys [f-insert# f-update#]} ~body]
(. ~component addMapListener
(proxy [AbstractMapListener] []
(entryInserted [~event] f-insert# ~event)
(entryUpdated [~event] f-update# ~event)))))
But in the end I'm not sure your code need a macro, have you tried to write it as a function:
(defn add-map-listener [component insert-fn update-fn]
(.addMapListener component
(proxy [AbstractMapListener] []
(entryInserted [e] (insert-fn e))
(entryUpdated [e] (update-fn e)))))
As you saw, I changed a couple of things:
body
) in some kind of special context.If you want to make the functions completely optional and make it possible to be given in any order you could always do that:
(defn add-map-listener [component & functions]
(let [{:keys [insert-fn update-fn]} (into {} functions)]
(when-not (empty? functions)
(.addMapListener component
(proxy [AbstractMapListener] []
(entryInserted [e] (insert-fn e))
(entryUpdated [e] (update-fn e)))))))
Notice that I've added code to not call addMapListener when no functions are given.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With