views:

64

answers:

1

what is the parameter to ns ? the documentation says something, but it's not clear (to me, at least)


my-new-namespace=> (doc ns)
-------------------------
clojure.core/ns
([name docstring? attr-map? references*])
Macro
  Sets *ns* to the namespace named by name (unevaluated), creating it
   if needed. 

...the rest of the documentation was not copied

the confusion comes from all the other functions that play with namespaces:


user=> (find-ns 'my-new-namespace)
nil
user=> (remove-ns 'my-new-namespace)
nil
user=> (create-ns 'my-new-namespace)
#<Namespace my-new-namespace>
user=> (ns 'my-new-namespace)
java.lang.ClassCastException: clojure.lang.PersistentList cannot be cast to clojure.lang.Symbol (NO_SOURCE_FILE:26)
user=> (ns my-new-namespace)
nil
my-new-namespace=>

find-ns, create-ns, remove-ns take my-new-namespace quoted, while ns takes my-new-namespace unquoted

so, what is the deal ? why some get a quoted form and others get and unquoted form of my-new-namespace ?

what is, in each case, my-new-namespace ?

ps: think i figured out the answer to this as i was writing the question here, but it seemed and interesting exercise, so the question still got posted :D

+1  A: 

ns is a macro and under the hood if quotes the name to save you the trouble:

user> (macroexpand '(ns foo))
    (do (clojure.core/in-ns (quote foo)) (clojure.core/with-loading-context   
        (clojure.core/refer (quote clojure.core))))

the other functions cant get away with unquoted arguments because they are functions, and functions have there arguments evaluated first.

the ns macro, as a macro, gets to look at and twiddle its arguments before they are evaluated so it can get at the my-new-namespace before the reader attempts to look it up as a variable name.

in short this saves wear and tare on your keyboard and wrists ;) Just kidding, the in both cases what the function receives is a symbol they just differ in what you have to do to pass them that symbol.

for comparason; if you where to go ahead and pass (ns 'my-new-namespace) it would get the symbol 'my-new-namespace quote and all! you likely don't want the quote to be part of the name space.

if you want to make it consistent you could write wrapper macros that take unquoted symbols for the rest of the namespace functions that simply quote the first argument and return a call to the real function (remember that macros return the code to be called)

(defmacro my-find-ns [name]
    `(find-ns (quote ~name)))

though this would break "the first rule of macro club"

the error about the argument being a list is caused by it attempting to use (quote my-new-namespace) as a name

 user> (macroexpand '(ns 'foo))
       (do (clojure.core/in-ns (quote (quote foo))) (clojure.core/with-loading-context
           (clojure.core/refer (quote clojure.core))))
Arthur Ulfeldt
thanks for introducing a new form (macroexpand) into my knowledge database :)
Belun
I usually use macroexpand-1 (less verbose). It helps to interpret error message strangeness
Arthur Ulfeldt