How to do namespace resolution in Clojure macros - clojure

I have a macro as such:
Example:
(defmacro xxz [& fns] `(:body ~#(map (fn [[e1 e2]] `(~e2 "http://www.google.com")) fns)))
If I pass something like (xxz [client/get client/get]), the resulting macroexpand shows that the symbols weren't qualified:
(:body (client/get "http://www.google.com"))
This causes problems when something like this lands in a namespace that doesn't have client imported.
Does anybody know what to do?

This sounds like a design oversight with syntax-quote (in my opinion), though it's not clear what a general "fix" would look like.
here is a more minimal example:
yummly.mobile-api.main> (in-ns 'foo)
#namespace[foo]
foo> (clojure.core/refer-clojure)
foo> (require '[org.httpkit.client :as client])
nil
foo> (defmacro xxz [& fns]
`(~#fns))
#'foo/xxz
foo> (macroexpand-1 '(xxz client/get))
(client/get)
from a new namespace:
foo> (in-ns 'bar)
#namespace[bar]
bar> (macroexpand-1 '(foo/xxz client/get))
(client/get)
bar> (foo/xxz client/get)
CompilerException java.lang.RuntimeException: No such namespace: client, compiling:(*cider-repl api*:87:6)
the syntax-quote-form (aka `) looks at every symbol in the expression as it's being compiled and if it does not find a / then it assumes it's for the local namespace and appends the current namespace. It can only do this for symbols that are present in the actual macro at the time the macro is defined, not (as I would like it to be able to do) for symbols that are passed as arguments to the macro.
If you use fully namespace qualified symbols in your macro then you don't need to worry if namepace where people use your macro has these symbols mapped to anything, because they spell out the full path to the symbol in it's name. If you don't want to actually type the full namespace in the symbols you use in your macro, then you can use :refer [get] in the require statement in your ns expression, this will save you having to type out the name and cause them to be correctly namespace expanded at the time that the macro definition is evaluated.
Because syntax quote is producing unhygenic symbols, you will need to either both :require or :refer to the functions in your ns section at the top of the namespace for every client where these namespaces are passed to the function.
Another option is to find some way to make sure the symbol is available to the macro at the time the syntax-quote is compiled. This can be tricky in some cases.

Related

How to reference a function within a macro in clojurescirpt?

I have a macro defined like so in macros.cljh file:
(defmacro db-event [event-key params & body]
`(do
(re-frame.core/reg-event-db ~event-key
(fn [~'db [_# ~#params]]
(deep-merge ~'db ~#body)))
(defn ~(symbol event-key) ~params (re-frame.core/dispatch [~event-key ~#params]))))
which references a function deep-merge. This macro is defined in the namespace myapp.macros. Yet when I use the macro in a cljs file, I get the error:
Use of undeclared Var myapp.macros/deep-merge
even though deep-merge is also defined in the myapp.macros namespace
I have the macro required in macros.cljs file like so too:
(ns myapp.macros
(:require-macros [myapp.macros]))
I tried adding this to the cljs namespace declaration:
(:require [myapp.macros :refer [deep-merge]])
But that gives a circular dependency error. What am I doing wrong in refereeing the deep-merge function?
Macros in ClojureScript are more complicated, and must adhere to a 2-stage compilation process.
See these links for starters, then search out other blog postings & docs as well
https://clojurescript.org/about/differences#_macros
https://blog.fikesfarm.com/posts/2016-03-01-clojurescript-macro-sugar.html
In particular, the macro must be defined in a *.cljc or *.clj file, then used in the *.cljs file. You can see some examples in action in this template project:
https://github.com/cloojure/cljs-template
I just checked and it still works, although it uses the old version of Figwheel and has not yet been upgraded to Figwheel-Main (aka Figwheel 2.0).
You should be able to define the macro in the macros.clj file with deep-merge in macros.cljs. As you’ve seen, you can’t introduce circular dependencies. Your goal is to require the namespace, with the macros. :require-macros ensures that if you require the namespace, the macros are included. You should be able to use the macro by requiring the namespace normally:
(ns myapp.core
(:require [myapp.macros :as macros]))
(db-event …)
An alternative solution, instead of calling :require-macros in macros.cljs, is to :require the namespace with :include-macros true. As an example,
In macros.clj:
(ns myapp.macros)
(defmacro twice
[& body]
`(twice-helper (fn []
~#body)))
In macros.cljs:
(ns myapp.macros)
(defn twice-helper
[f]
(f)
(f))
Then we can use the macro in core.cljs:
(ns myapp.core
(:require [myapp.macros :as macros :include-macros true]))
(macros/twice (println "hello!"))

Resolve symbol in macro

I am stuck on a seemingly basic thing. I have a namespace where I have some definitions:
(ns my-namespace)
(def my-definition "HELLO")
(def my-definition2 "HI")
Now, I want to use the value of the vars in my-namespace in a macro, but I want to retrieve the symbols dynamically. E.g.,
(defmacro my-macro [n]
(-> "my-namespace/my-definition" symbol resolve var-get))
Retrieving a symbol in such a manner works in a function (as long as the namespace is loaded), but not in a macro.
In a macro, the symbol cannot be resolved. I've tried quoting and unquoting but it still does not work.
Is it possible in a macro to use the value of a symbol created like that? If so, how?
Try this one:
(defmacro my-macro
[str]
(-> str symbol resolve deref))
The symbol cannot be resolved, because the namespace where it is defined is not loaded. You can load namespace by
(require 'my-namespace)
or in namespace declaration:
(ns macro-expansion-ns
(:require [my-namespace]))

How to make symbol(s) from namespace accessible in all namespaces w/o qualifier?

I have namespace with debug utilities that are used only in development. I'd like to make them accessible in all namespaces without qualifier (same as symbols from clojure.core).
Let's say my project structure is as follows:
dbg_utils.clj:
(ns project.dbg-utils)
(defmacro dbg ...)
db.clj
(ns project.db)
(defn create-entity [...]
...)
After I'd like to fire up REPL and type something like this:
> (require 'project.db)
> (require 'project.dbg-utils)
> (globalize-symbol 'project.dbg-utils/dbg)
And after use dbg macro without qualifier:
(ns project.db) ;; no require of project.dbg-utils
(defn create-entity [...]
(dbg ...) ;; and no qualifier here
...)
Is anything like globalize-symbol (or close to this) available?
Leiningen provides the :injections feature and the :user profile for that.
This article shares some pointers on how to do that. It basically works by adding the debugging functions you want to clojure.core and since all public vars from this namespace are always included when using the ns macro (unless you specify otherwise), you will have them available in all your namespaces.

Using variables declared in another namespace

I have a dictionary of words stored in a vector in one ns (ns dictionary.core) and I want to have access the vector in another namespace, for example, (ns clojure-project.core) How should I do it? I have been researching the concept of namespaces for some time and I am still confused as to how I can "import" variables defined in another file into my current project.
(ns clojure-project.core
(:require [dictionary.core :as dict]))
(defn choose-a-word []
(rand-nth (dict/words)))
Namespace declarations have many options, so it can be very confusing! Limiting yourself to the above form is in my opinion good style.

difference between use and require

Can anyone explain the difference between use and require, both when used directly and as :use and :require in the ns macro?
require loads libs (that aren't already loaded), use does the same plus it refers to their namespaces with clojure.core/refer (so you also get the possibility of using :exclude etc like with clojure.core/refer). Both are recommended for use in ns rather than directly.
It's idiomatic to include external functions with require and refer. You avoid namespace conflicts, you only include functions you actually use/need, and you explicitly declare each function's location:
(ns project.core
(:require [ring.middleware.reload :refer [wrap-reload]]))
I do not have to invoke this function by prefixing it with its namespace:
(wrap-reload) ; works
If you don't use refer you'll need to prefix it with the namespace:
(ring.middleware.reload/wrap-reload) ; works if you don't use refer in your require
If you choose use instead, (pretty much) always use only:
(ns project.core
(:use [ring.middleware.reload :only [wrap-reload]]))
Otherwise you're including everything, making it both an unnecessarily large operation and very confusing for other programmers to find where the functions live.
Also, I highly recommend this blog as a resource for learning more about Clojure namespaces.
Use sure does make it easier by not requiring you to spell out the namespace every time you want to call a function though it can also make a mess of things by creating namespace conflicts. A good middle ground between "use" and "require" is to only 'use' the functions from a namespace that you actually use.
for instance:
(use '[clojure-contrib.duck-streams :only (writer reader)])
or even better, specify it at the top of the file in the namespace definition:
(ns com.me.project
(:use [clojure.contrib.test-is :only (deftest is run-tests)]))
As has been mentioned the big difference is that with (require 'foo), you then refer to names in the lib's namespace like so: (foo/bar ...) if you do (use 'foo) then they are now in your current namespace (whatever that may be and provided there are no conflicts) and you can call them like (bar ...).