On Thu, Apr 28, 2011 at 6:36 AM, MohanR <radhakrishnan.mo...@gmail.com> wrote:
> There should be a way to print the currently executing function and
> the calling function logging purposes ?
>
> I believe Java has StackTraceElement[] to do this.

And therefore so does Clojure:

user=> ((fn foo [] (map #(.getClassName %) (.getStackTrace (Throwable.)))))
("user$eval1738$foo__1739"
 "user$eval1738"
 "clojure.lang.Compiler"
 "clojure.lang.Compiler"
 "clojure.lang.Compiler"
 "clojure.core$eval"
 "user$eval1736"
 "clojure.lang.Compiler"
 "clojure.lang.Compiler"
 "clojure.core$eval"
 "clojure.main$repl$read_eval_print__5624"
 "clojure.main$repl$fn__5629"
 "clojure.main$repl"
 "clojure.lang.RestFn"
 "org.enclojure.repl.main$create_clojure_repl$repl_thread_fn__1247"
 "clojure.lang.AFn"
 "java.lang.Thread")

You can get the "foo" out of the first element with enough regexp
hackery I expect, but if handed a random function object it won't be
as easy as if you are *inside* the function. If the function can be
relied on to call one you pass it, then maybe you can: pass it a
function that generates a traceback and stores it somewhere you can
retrieve it, then look for a stack trace element below yourself. Even
then it's tricky:

(def st (atom nil))

(defn save-st [& _]
  (reset! st (map #(.getClassName %) (.getStackTrace (Throwable.)))))

(defn get-mangled-name [f p-template]
  (apply f (map #(if (= % :here) save-st %) p-template))
  (first
    (filter identity
      (map #(if (> (.indexOf %2 "get_mangled_name") -1) %1)
        @st
        (rest @st)))))

(defn callifier [x f] (f x))

user=> (get-mangled-name callifier [3 :here])
"clojure.core$apply"

Argh.


user=> @st
("user$save_st"
 "clojure.lang.RestFn"
 "user$callifier"
 "clojure.lang.AFn"
 "clojure.lang.AFn"
 "clojure.core$apply"
 "user$get_mangled_name"
 ...)

WTF? Seems a bit inefficient, but OK.

(defn get-mangled-name [f p-template]
  (apply f (map #(if (= % :here) save-st %) p-template))
  (first
    (filter identity
      (map #(if (> (.indexOf %2 "get_mangled_name") -1) %1)
        @st
        (drop 4 @st)))))

user=> (get-mangled-name callifier [3 :here])
"user$callifier"

Aha!

user=> (get-mangled-name map [:here [1 2 3]])
"user$callifier"

WTF??!

user=> (reset! st ["foo" "bar" "baz" "quux" "get_mangled_name"])
["foo"
 "bar"
 "baz"
 "quux"
 "get_mangled_name"]
user=> (get-mangled-name map [:here [1 2 3]])
"foo"

O-Damn: map is lazy, so save-st never gets called to overwrite the
atom contents.

OK, then:

(defn get-mangled-name [f p-template]
  (let [x (apply f (map #(if (= % :here) save-st %) p-template))]
    (if (instance? clojure.lang.LazySeq x) (doall x)))
  (first
    (filter identity
      (map #(if (> (.indexOf %2 "get_mangled_name") -1) %1)
        @st
        (drop 4 @st)))))

user=> (get-mangled-name map [:here [1 2 3]])
"clojure.lang.RT"

AAAAAAA

<img src=http://tinyurl.com/argggh>

RRRGH!

user=> @st
("user$save_st"
 "clojure.lang.RestFn"
 "clojure.core$map$fn__3695"
 "clojure.lang.LazySeq"
 "clojure.lang.LazySeq"
 "clojure.lang.RT"
 "clojure.core$seq"
 "clojure.core$dorun"
 "clojure.core$doall"
 "user$get_mangled_name"
 ...)

(defn get-mangled-name [f p-template]
  (let [x (apply f (map #(if (= % :here) save-st %) p-template))]
    (if (instance? clojure.lang.LazySeq x) (doall x)))
  (let [a (fn [n]
            (first
              (filter identity
                (map #(if (> (.indexOf %2 "get_mangled_name") -1) %1)
                  @st
                  (drop n @st)))))
        y (a 4)
        n (if (= y "clojure.lang.RT") (a 7) y) ; mega hack!
        n (.substring n (inc (.indexOf n "$")))
        i (.indexOf n "$")]
    (if (> i -1)
      (.substring n 0 (.indexOf n "$"))
      n)))

user=> (get-mangled-name callifier [3 :here])
"callifier"
user=> (get-mangled-name map [:here [1 2 3 4 5]])
"map"
user=> (get-mangled-name filter [:here [1 2 3 4 5]])
"filter"

It works! It w...

user=> (get-mangled-name reduce [:here [1 2 3 4 5]])
"r"

...orks?

user=> (get-mangled-name (fn foo [f z] (f z)) [:here [1 2 3 4 5]])
"eval2194"
user=> (get-mangled-name #(+ %1 (%2 %1)) [3 :here])
#<CompilerException java.lang.ClassCastException: clojure.lang.LazySeq
cannot be cast to java.lang.Number (NO_SOURCE_FILE:336)>

*sob*

So, it won't work if it's not a HOF that calls one of its arguments.
It won't work if the fn is not top-level. It won't work if the
function throws up when it sees save-st's output, though wrapping a
catch-all try around (let [x ...]) might fix that. And of course if
the function has side effects God help you.

I don't think this approach is very workable for getting the names of
arbitrary functions -- only yourself and functions that have called
you.

Better to just use the metadata, which works on every function for
which get-mangled-name works, and won't mangle - to _.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to