10

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.

enter image description here

The error message from not quoting is also confusing.

prosseek
  • 182,215
  • 215
  • 566
  • 871

2 Answers2

9

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.

Michiel Borkent
  • 34,228
  • 15
  • 86
  • 149
5

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.

Davyzhu
  • 1,109
  • 9
  • 17