marginalia icon indicating copy to clipboard operation
marginalia copied to clipboard

macros

Open fconcklin opened this issue 13 years ago • 3 comments

Marginalia seems to be evaluating macros. This can be problematic.

https://gist.github.com/941466

fconcklin avatar Apr 25 '11 23:04 fconcklin

Here is an example where everything goes wrong https://gist.github.com/941481

fconcklin avatar Apr 25 '11 23:04 fconcklin

I was able to get around this with (eval (macroexpand (call-to-macrodefined-fn)))

fconcklin avatar Apr 26 '11 00:04 fconcklin

Marginalia evaluates macros to handle def* macros. To be able to strip the docstring wherever it is in the definition, it currently check the actual var docstring and strip it off from the parsed code. I'm not sure there's a better way to do that. Anyway in most cases macro shouldn't have side-effects. In the case of debugging macros like in your example, you might try this other approach:

(def *dbg* false)

(defmacro dbg [x]
  (if *dbg*
    `(let [x# ~x]
       (println '~x "=" x#)
       x#)
    x))

(defn pythag [x y]
  (dbg (* (dbg (* x x))
          (dbg (* y y)))))

(pythag 4 5)

;; no output

(def *dbg* true)

(defn pythag [x y]
  (dbg (* (dbg (* x x))
          (dbg (* y y)))))

(pythag 4 5)

;; (* x x) = 16
;; (* y y) = 25
;; (* (dbg (* x x)) (dbg (* y y))) = 400

The only issue with this code is that if you rebind dbg dynamically, you'll need to expand the macros recursively at compile time which (in the case you use a simple walker) will have expanded you inner calls to dbg:

(use 'clojure.walk)

(defmacro with-dbg [x]
  (binding [*dbg* true]
    (prewalk #(macroexpand %) x)))

(with-dbg
  (defn pythag [x y]
    (dbg (* (dbg (* x x))
            (dbg (* y y))))))

(pythag 4 5)

;; (* x x) = 16
;; (* y y) = 25
;; (* (let* [x__4681__auto__ (* x x)] (clojure.core/println (quote (* x x)) = x__4681__auto__) x__4681__auto__) (let* [x__4681__auto__ (* y y)] (clojure.core/println (quote (* y y)) = x__4681__auto__) x__4681__auto__)) = 400

budu avatar Apr 27 '11 20:04 budu