Reputation: 65
What I am trying to achieve is to implement an abstract class with reify inside a macro, but the expressions that should return on expansion time would be supplied to the macro quoted:
(defmacro a-printable
[body]
`(reify Printable
(print [this g# pf# page#]
(if (= page# 0)
(do
~body ;; the supplied part
(Printable/PAGE_EXISTS))
(Printable/NO_SUCH_PAGE)))
(def exp '(do (.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))) ;; the form to pass
(a-printable exp)
The proplem is that in the expression I pass, I want to use the automatic generated vars defined inside the macro and inside reify g#, pf#
.
I tried to add the quoted expression with (ns-resolve *ns* g)
(ns-resolve *ns* pf)
but with no lack, I am not sure that is being resolved inside the macro.
The g
is java.awt.Graphics
which is an abstract class and the pf
is java.awt.print.PageFormat
, which is normal class with constructor.
Does anyone has any idea how to achieve that, or turn me to the correct direction?
Upvotes: 0
Views: 107
Reputation: 4901
I believe the trick is that if you don't want namespaced symbols in a macro, you can prefix them with ~'
, e.g. ~'g
. Then I did the following other modifications to your macro:
body
parameter with &
to make it variable length.(Printable/PAGE_EXISTS)
and (Printable/NO_SUCH_PAGE)
: Those are static variable values that you want to return, not function calls. This is what the fixed macro looks like:
(defmacro a-printable
[& body]
`(reify Printable
(print [~'this ~'g ~'pf ~'page]
(if (= ~'page 0)
(do
~@body ;; Splice it!
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
And this is how you create an instance. Note that I do not need to wrap the argument to the macro with do
:
(def p (a-printable
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10)))
A note however: I am not sure it is a good practice to introduce new symbols, such as pf
and g
, but I cannot find the reference mentioning why that would be a bad practice. There are ways of achieving similar things to what is being asked in this question without resorting to macros. The version that does not use macros is not much longer:
(defn a-printable-fn [body-fn]
(reify Printable
(print [this g pf page]
(if (= ~'page 0)
(do
(body-fn this g pf page)
Printable/PAGE_EXISTS)
Printable/NO_SUCH_PAGE))))
(def p (a-printable-fn
(fn [this g pf page]
(.translate g (.getImageableX pf) (.getImageableY pf))
(.drawString g "foo" 10 10))))
Upvotes: 1