Determine namespace of a function's caller - clojure

I'm trying to accurately determine the namespace of a function's caller. Looks like *ns* is determined by the namespace at top of the call stack.
user=> (ns util)
nil
util=> (defn where-am-i? [] (str *ns*))
#'util/where-am-i?
util=> (ns foo (:require [util]))
nil
foo=> (util/where-am-i?)
"foo"
foo=> (ns bar)
nil
bar=> (defn ask [] (util/where-am-i?))
#'bar/ask
bar=> (ask)
"bar"
bar=> (ns foo)
nil
foo=> (util/where-am-i?)
"foo"
foo=> (bar/ask)
"foo"
foo=>
Is there some other meta data I can rely on or do I need to specify this manually?

This is not possible. In the repl, *ns* is always set to the namespace in which the repl is; at runtime it is usually clojure.core, unless someone goes to the trouble to set it, which is uncommon.

I'm not sure what your complete use case is, but judging from your example you want #'bar/ask to return its own namespace instead of returning a function that resolves the current namespace. You could simply use def instead of defn. Here is an example following on from what you did:
util=> (in-ns 'bar)
#<Namespace bar>
bar=> (def tell (util/where-am-i?))
#'bar/tell
bar=> (in-ns 'foo)
#<Namespace foo>
foo=> (refer 'bar :only '[tell])
nil
foo=> tell
"bar"
Hope this helps!

Related

Configure symbol quote expansion in clojure zprint

Is there a way to avoid having zprint write 'my-symbol as (quote my-symbol)? I am aware it is the reader that converts it to that form.
However I would expect zprint to be configurable to produce the more idiomatic format which is the default for clojure.pprint.
(require '[zprint.core :as zp])
(zp/zprint '(def foo 'my-symbol))
;; (def foo (quote my-symbol))
(require '[clojure.pprint :as pp])
(pp/pprint '(def foo 'my-symbol))
;; (def foo 'my-symbol)
See related issue:
https://github.com/kkinnear/zprint/issues/121
Following bfabry's comment, as a workaround, we can use pprint to create the nicely quoted string, and then pass it through zprint for formatting:
(require '[zprint.core :as zp])
(require '[clojure.pprint :as pp])
(-> '(def foo 'my-symbol)
pp/pprint
with-out-str
(zp/zprint 40 {:parse-string? true}))
(def foo 'my-symbol)
nil

Clojure - same function name different namespace

I am trying to do the following:
(ns ns-test.core
(:use [ns-test.a :as a]
[ns-test.b :as b]))
(def test-map {:key "a"})
(defmulti print-ns :key)
(defmethod print-ns "a" [input-map]
(a/foo input-map))
(defmethod print-ns "b" [input-map]
(b/foo input-map))
with namespaces a and b that look like this:
(ns ns-test.a)
(defn foo [x]
(println x "I'm in namespace A."))
and
(ns ns-test.b)
(defn foo [x]
(println x "I'm in namespace B."))
but when I try to load these classes into the REPL, I get this:
user=> (use 'ns-test.core :reload)
CompilerException java.lang.IllegalStateException: foo already refers to: #'ns-test.a/foo in namespace: ns-test.core, compiling:(ns_test/core.clj:1:1)
Why does this conflict between a/foo and b/foo exist, and how can I prevent it? (Isn't the whole point of namespaces and namespace qualification to allow me to have two different functions of the same name?)
You probably wanted to :require the namespaces a and b instead of :use. :use interns the namespace symbols to the current namespace, thus the conflict.

How to unload a function from another namespace?

I load a function say-hi from namespace learning.greeting
(use 'learning.greeting)
When I try to re-defn the say-hi function under the current (user) namespace, I got the error:
CompilerException java.lang.IllegalStateException: say-hi already refers to: #'learning.greeting/say-hi in namespace: user, compiling:(NO_SOURCE_PATH:1:1)
So how to unload the function from other namespaces?
If you want to get rid of a direct mapping to a Var from another namespace at the REPL, say
(ns-unmap 'current-namespace 'local-alias)
Example:
user=> (ns-unmap *ns* 'reduce)
nil
user=> (reduce + 0 [1 2 3])
CompilerException java.lang.RuntimeException: Unable to resolve symbol: reduce in this context, compiling:(NO_SOURCE_PATH:2:1)
Local alias will differ from the actual name of the Var if :rename was used:
(use '[clojure.walk
:only [keywordize-keys]
:rename {keywordize-keys keywordize}])
To remove all mappings pointing at Vars in clojure.walk:
(doseq [[sym v] (ns-map *ns*)]
(if (and (var? v)
(= (.. v -ns -name) 'clojure.walk))
(ns-unmap *ns* sym)))
Do you really want to remove say-hi from learning.greeting? If not, it might be better to use require in this situation. Instead of (use 'learning.greeting), execute:
(require `[learning.greeting :as lg])
Then you can refer to the original definition as lg/say-hi, and you can define a new version in the current namespace, e.g. as
(def say-hi [x] (lg/say-hi (list x x))
(I don't know whether that makes sense for the say-hi function, but the general point is the same regardless.)
both use and require have an :exclude parameter for just this situation:
(use '[learning.greeting :exclude [say-hi]])
or more preferably use require:
(require '[learning.greeting :refer :all :exclude [say-hi]])
or when you are working in a normal namespace putting all this in the ns form is preferred:
(ns my-namespace
(:require [learning.greeting :refer [ function1 function2] :as greeting]

Forward-declaring a var from another namespace in Clojure?

I know how to forward declare a var for the current namespace. Instead, I want to declare a var from another namespace. How do I do this? This will help me eliminate a circular load dependency.
At the moment, this is what I've tried:
; this_ns.clj
(ns my-project.this-ns
(:require ...))
(ns my-project.other-ns)
(declare other-func)
(ns my-project.this-ns) ; return to original namespace
(defn func-1
[]
(my-project.other-ns/other-func))
It works, but I don't like it.
I think the solution you already have is the easiest one. If you wrap it into a macro it doesn't even look that bad anymore:
(defmacro declare-extern
[& syms]
(let [n (ns-name *ns*)]
`(do
~#(for [s syms]
`(do
(ns ~(symbol (namespace s)))
(declare ~(symbol (name s)))))
(in-ns '~n))))
Call it with:
(declare-extern my.extern.ns/abc) ;; => #<Namespace ...>
my.extern.ns/abc ;; => #<Unbound Unbound: #'my.extern.ns/abc>

get a clojure function's code

Is there a way in clojure to get a function's code after the function has been loaded?
Ie. without doing something like [untested]
(defmacro blat [x] `(do (def code ~(quote (mexpand-all x)))
~x)))
(blat (defn func [abc] (...)))
You can get the source of a symbol using the clojure.repl/source function. However, this only works if the var for which the symbol resolves to is in a .clj file on the classpath. You can't, for example, do this:
user=> (defn foo [x] x)
#'user/foo
user=> (require 'clojure.repl)
nil
user=> (clojure.repl/source foo)
Source not found
nil