In his Clojure Style Guide the author writes the following,
Prefer using :require :refer :all over :use in ns macro
He does not give any explanation why this is a good idea. Is there a good reason to avoid the use of :use in the ns macro?
I'd suggest you take a look at the original discussion, which lead to this rule. The core rationale can be found here. I'll include here the start of the discussion:
There's been discussion previously about the complexity of the ns macro. In particular the fact that :use causes all vars to be referred by default is widely seen as unfortunate, and the distinction between use and require is a source of conceptual overhead for people new to the language. We can't change the fact that :use refers everything by default without breaking lots of existing code. But it would be possible to enhance :require to support referring specified vars, leaving us free to deprecate or otherwise discourage the use of :use.
Rather than this form:
(ns mork.test (:use [mork.stats :only [summarize-group]] [mork.utils :only [strip resolve-fn]] [clojure.test]) (:require [mork.view :as view] [clojure.java.io :as io] [cheshire.core :as json]) (:import (java.io PushbackReader))
We could use this:
(ns mork.test (:require [mork.stats :refer [summarize-group]] [mork.utils :refer [strip resolve-fn]] [clojure.test :refer :all] [mork.view :as view] [clojure.java.io :as io] [cheshire.core :as json]) (:import (java.io PushbackReader))
It has been agreed upon in previous threads that keeping :import as a distinct concept from :require is desirable, and I agree that we shouldn't conflate between Clojure vars and Java classes.
There are rare cases when referring all the vars in a namespace is acceptable, (in particular when writing test namespaces it seems reasonable to bring in all of clojure.test and the namespace under test) so we should probably support :refer :all for such a case, as long as it's not the default.
My impression is that there are two reasons. 1) In doing so, you are more likely to avoid any name clashes and/or accidental overshadowing. 2) Such practices give greater transparency about the ultimate source of the functions and variables used in the code. The first one is pretty practical, and Chiron's answer provides a great demonstration.
The second one is more subtle, but if you are using a lot of libraries, it can be pretty important. Let's say you do:
(ns your-namespace
(:use [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
And then somewhere, later in your code, you invoke:
(important-function some-arg some-other-arg)
If important-function
is defined in, for example, library-three
, then you (or whoever is trying to make sense of your code) have to go digging through each of those libraries' code to figure out what it does--because there's nothing to indicate which library is its source! Well, actually, if you have a REPL available, you should be able to figure it out by doing:
your-namespace> `important-function
> library-three/important-function
But that kind of hidden information is probably not the best thing to inflict on other people (including your future self) who may wish to understand your code. On the other hand, :require
d libraries always come with a prefix. So instead, your code would look like:
(ns your-namespace
(:require [library-one]
[library-two]
[library-three]
[library-four]
[library-five]))
...
(library-three/important-function some arg some-other-arg)
Which makes it very clear where important-function
is defined. Note that this should be equivalent to specifying :refer :all
. Although :refer :all
could indicate to others that you considered specifically which vars to reference, and made a conscious decision to include all of them from that library.
If you are not worried about name clashing...well you probably should be. But if you still aren't, and you want to be clear about vars' sources, then you could always do :use
with :only
. For example:
(ns your-namespace
(:use [library-one :only []]
[library-two :only []]
[library-three :only [important-function]]
[library-four :only []]
[library-five :only []]))
...
(important-function some arg some-other-arg)
Obviously, if you are :use
ing libraries with blank :only
vectors, than you might as well not :use
them in the first place, I just wanted to unify with the previous examples. And doing :require
may seem verbose, but you can always shorten it by aliasing with :as
. Fragment example:
(ns your-namespace
(:require [library-three :as L3]))
(L3/important-function some-arg some-other-arg)
See also, this SO question, and this guide about libraries and namespaces in Clojure.
Because with :require
you will have a clear indication which namespace owns a function.
(:require [clojure.json :as json])
(:require [clojure.xml :as xml])
(json/read "file")
(xml/read "file")
In case of :use
(read "file")
How you are going to know which namespaces owns read
function? If I'm maintaining your code, I have to check ns
macro and start searching for read
function in each use
qualified namespace.
Separation of concerns. require
let you load namespaces, refer
let you define how you refer to vars within those namespaces. use
complects the two concerns.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With