user5684480
user5684480

Reputation:

a binding in a macro isn't resolved

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

Answers (2)

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:

vars

Upvotes: 3

leeor
leeor

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

Related Questions