目前扩展协议定义的函数在堆栈跟踪中看起来像这样
at app.core$eval3547$fn__3548.invoke(core.clj:23)
at app.core$eval3522$fn__3523$G__3513__3532.invoke(core.clj:14)
不用说,这些并不完全具有描述性。更不用说它所引用的行是 extend-protocol 和 defprotocol 被调用的地方,而不是函数定义的地方。
我希望得到类似 app.core/MyProtocol/IfaceImplemented/函数名_1234
的东西,其中的行号位于“违规”代码片段的位置,而不是定义的位置。
我在本地稍作修改,发现修改 emit-method-builder、emit-impl 和 emit-hinted-impl 稍微做了些修改,使堆栈跟踪更易于阅读。
黑客差异
diff --git a/src/clj/clojure/core_deftype.clj b/src/clj/clojure/core_deftype.clj
index 786f0d4b..73570dbf 100644
--- a/src/clj/clojure/core_deftype.clj
+++ b/src/clj/clojure/core_deftype.clj
@@ -586,9 +586,10 @@
(defn- emit-method-builder [on-interface method on-method arglists extend-via-meta]
(let [methodk (keyword method)
- gthis (with-meta (gensym) {:tag 'clojure.lang.AFunction})
- ginterf (gensym)]
- `(fn [cache#]
+ gthis (with-meta (gensym (str method)) {:tag 'clojure.lang.AFunction})
+ ginterf (gensym)
+ giface-name (gensym (last (.split (name on-interface) "\\.")))]
+ `(fn ~giface-name [cache#]
(let [~ginterf
(fn
~@(map
@@ -812,9 +813,21 @@
(:var proto)))))
(-reset-methods (alter-var-root (:var proto) assoc-in [:impls atype] mmap))))
+(defn- iface-fn-name
+ ([p f]
+ (iface-fn-name "" p f))
+ ([c p f]
+ (let [c-name (cond
+ (symbol? c)
+ (last (.split (name c) "\\."))
+ (nil? c)
+ "nil"
+ :else nil)]
+ (symbol (str p (when c-name (str "__" c-name)) (first f))))))
+
(defn- emit-impl [[p fs]]
[p (zipmap (map #(-> % first keyword) fs)
- (map #(cons `fn (drop 1 %)) fs))])
+ (map #(cons `fn (cons (iface-fn-name p %) (drop 1 %))) fs))])
(defn- emit-hinted-impl [c [p fs]]
(let [hint (fn [specs]
@@ -826,7 +839,7 @@
body))
specs)))]
[p (zipmap (map #(-> % first name keyword) fs)
- (map #(cons `fn (hint (drop 1 %))) fs))]))
+ (map #(cons `fn (cons (iface-fn-name c p %) (hint (drop 1 %)))) fs))]))
(defn- emit-extend-type [c specs]
(let [impls (parse-impls specs)]
之后的日志
at app.core$eval3965$ProtocolName__ClassName__FnName__3966.invoke(core.clj:23)
at app.core$eval3940$ProtocolName3932__3941$__FnName3930__3950.invoke(core.clj:14)