I have a problem constructing a DSL in Clojure. This is the concrete problem I have isolated from everything else.
Let’s say we hava a simple macro:
user> (defmacro m1 [x] `'~x)
#'user/m1
it just returns the literal supplied
user> (m1 toUpperCase)
toUpperCase
if we call java method for object everything works as expected
user> (. "a" toUpperCase)
"A"
but if we substitute method name for macro call that returns the methodname
user> (. "a" (m1 toUpperCase))
; Evaluation aborted.
Unable to resolve symbol: toUpperCase in this context
I want to use some java library that has fluent interface like a().b().c().
This maps to Clojure as:
(.. obj method1 method2 method3....etc)
I want to create macros that substitute some parts of this chain so my code should be like:
(.. obj method1 macro1)
and that should expand to
(.. obj method1 method2 method3)
definline also doesn’t help. I tried that also
The reason you’re running into this problem is that the . special form does not evaluate its second argument (the symbol specifying the method or field) in the way you expect: it sees it as a call of the METHOD m1, with the ARGUMENT toUppercase. Because of that, you cannot generate the symbol for the method dynamically just as an argument to . (dot) – even if you use a macro to specify that argument.
A way to work around that is to include the . in your macro:
Note that you need to wrap parentheses around ~y to indicate you want to call a method instead of reading a field.