I see that we don't need ' with (ns ...)
as ns is a macro.
However, why do we need ' in (require '[...])
? I thought that Clojure's vector is a fancy way to avoid ', but now I see one here.
We use (require 'clojure.string)
so require
seems to be a function, but we don't quote a vector when given as a parameter.
The error message from not quoting is also confusing.
This is because require
is implemented as a function and not a macro, hence it needs a quoted libspec. An unquoted libspec would be evaluated like this:
user=> [clojure.set :as s]
CompilerException java.lang.ClassNotFoundException: clojure.set
thus yielding an error.
However, ns
is implemented as a macro and has full control over if or when to evaluate its arguments any further, so you don't need to quote the libspec. You can look at a macroexpansion of ns and see what happens when it is expanded:
user=> (use 'clojure.pprint)
nil
user=> (pprint (macroexpand '(ns foo (:require [clojure.set :as s]))))
(do
(clojure.core/in-ns 'foo)
(clojure.core/with-loading-context
(clojure.core/refer 'clojure.core)
(clojure.core/require '[clojure.set :as s]))
(if
(.equals 'foo 'clojure.core)
nil
(do
(clojure.core/dosync
(clojure.core/commute
@#'clojure.core/*loaded-libs*
clojure.core/conj
'foo))
nil)))
nil
As you can see, ns
just takes the libspec as it is and quotes it for you before passing it to require, so you don't have to.
The niche is: Quoting a vector is essentially quoting every sub-forms inside the vector form.
user> (= '[a b c] ['a 'b 'c])
=> true
The require
form can take either a quoted symbol, referencing a namespace, or it can take a vector of quoted symbols putting further restrictions.
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