Reputation:
I'm creating a library for an API server, here's a simpliefied version of I have:
(defonce ^:dynamic *my-token* nil)
(defmacro def-my-token
[token1 & body]
`(binding [*my-token* ~token1] ~@body))
And the main "post" method:
(defn my-post-request [url1]
(try
(let [res (client/post (str "api/url/base" url1)
{:body (json/write-str (:secret my-token)) ; my-token should come from the macro
;......
And here's how I want to use it:
(defn -main [& args]
(def-my-token "fdsfdsfdsfds"
; now "my-token" should be created and visible in "my-post-request", shouldn't it?
(print
(my-post-request "/some_end_point"))))
But it says "Unable to resolve symbol: my-token in this context"
I wonder why? doens't def-my-token, being a macros, define it? why not? And how to fix that?
UPDATE:
Also without (defonce ^:dynamic *token* nil)
it doesn't work. Why not?
Why isn't defining the macro enough?
Upvotes: 2
Views: 148
Reputation: 506
Answer to your UPDATE:
According to the documentation for binding, you can only override already existing vars. That's why your solution doesn't work without establishing a root binding to your dynamic var.
Sidenote:
I would recommend doing what jmargolisvt said and use a plain def
instead of defonce
, as I've never seen any dynamic var definition in the wild using defonce
.
EDIT:
doens't def-my-token, being a macros, define it? why not? And how to fix that?
Macros by themselves don't define things, they are small programs transforming your source code in the macro-expansion step of most Lisp REPL
's. It could define anything you want it to, but then you should've wrote the def
special form. What you used instead was binding
which deals with already existing vars.
You might get more insight by toying with it in the REPL and/or reading the answer of this stackoverflow answer.
If you need some further explanation why overriding
is needed:
It's practical to conceptualize vars as stacks. The root binding that you establish with using def
is the first layer. Everything in your program will see this value unless you put "something" over it. As you can imagine in your example having *my-token*
seen as nil
from your functions would cause issues.
binding
to the resuce!
It allows you put anything "on top" of the root binding (in your case nil
) thread-locally inside of the body it, like so:
Upvotes: 3
Reputation: 17781
you bound *my-token*
, not my-token
. Try:
{:body (json/write-str (:secret *my-token*))
The asterisks are just a naming convention for dynamic vars, they are still part of the actual var name.
Upvotes: 2