Reputation: 4643
If I have a symbol who's namespace is an alias, like q/w, how can I find its actual namespace, say actual.namespace/w ?
I know that resolve
will give me the fully qualified var, but I don't know how to get the namespace of a var.
The best I can do is:
(defn fqns [s] (str (get (ns-aliases *ns*) (symbol (namespace s)))))
surely there's a simpler way ?
Upvotes: 4
Views: 3271
Reputation: 84331
The symbol itself has no direct connection to any namespace object; its namespace part is just an interned string. It is only when it's being resolve
d that this string is treated as the name of an actual namespace in which to look up a Var. (In particular, you can create a symbol foo/bar
without creating a namespace foo
or registering foo
as an alias for a namespace.) Thus, you need to either go through resolve
or do part of its work yourself.
In the first case, you can say (in recent versions of Clojure; or you can skip the hyphens signifying property access -- instead of -ns
, use ns
-- to be backwards compatible)
(.. (resolve s) -ns -name)
This resolves a Var object, then extracts a reference to its namespace from its ns
field and finally extracts the symbolic name of the namespace from its name
field. (Note that the namespace
and name
functions wouldn't work, since Vars and namespaces do not implement clojure.lang.Named
.)
The function from the question text is fine too, although it'll be better to extract the symbol name from the namespace -- (.-name (get ...))
-- rather than rely on the toString
representation of namespaces through the use of str
.
You may also want to add clojure.lang.Var
and clojure.lang.Namespace
type hints to avoid reflection in your calls. (If you want them to be faster, or if you need *warn-on-reflection*
to tweak something else for performance and wish to avoid useless warnings here.)
If you wish to handle the possibility that the namespace does not exist (and return nil
in that case, in keeping with usual Clojure idiom):
(defn fqns
([s]
(fqns (.-name *ns*) s))
([ns s]
(some-> ns
find-ns
.-name
ns-aliases
(get (symbol (namespace s)))
.-name)))
Or use some if-let
s in Clojure 1.4 and earlier.
Upvotes: 2
Reputation: 33637
You can get the namespace object of a symbol as shown below (if you want name of ns as string then just call str at the end):
(defn fqns [s] (->> (resolve s) meta :ns))
Upvotes: 8