2024年的Clojure调查中分享您的想法!

欢迎!请参阅关于页面,了解有关此功能的更多信息。

+6
错误
描述用户面临的问题

当抛出异常并在堆栈跟踪中有多方法时,多方法的名称不会显示在调用堆栈中。

当我执行以下代码时


(defmulti dispatcher (fn [item] (:type item)))

(defmethod dispatcher "cat"
  [{:keys [lives]}]
  (/ lives 0))

(dispatcher {:type "cat" :lives 9})
*e


我得到以下堆栈跟踪


[clojure.lang.Numbers divide "Numbers.java" 163]
[clojure.lang.Numbers divide "Numbers.java" 3813]
[config_compilation.core$eval20467$fn__20469 invoke "/Users/marc/dev/circleci/orb-registry/server/src/config_compilation/core.clj" 198]
[clojure.lang.MultiFn invoke "MultiFn.java" 229]
... 省略 ...


函数名称是 {{config_compilation.core$eval20467$fn__20469}}。

如果我使用 {{defn}} 直接声明 {{dispatcher}},我将得到以下堆栈跟踪


(defn dispatcher
  [{:keys [lives]}]
  (/ lives 0))

(dispatcher {:type "cat" :lives 9})
*e



[clojure.lang.Numbers divide "Numbers.java" 163]
[clojure.lang.Numbers divide "Numbers.java" 3813]
[config_compilation.core$dispatcher invokeStatic "/Users/marc/dev/circleci/orb-registry/server/src/config_compilation/core.clj" 202]
[config_compilation.core$dispatcher invoke "/Users/marc/dev/circleci/orb-registry/server/src/config_compilation/core.clj" 200]
... 省略 ...


函数名称正确给出为 {{config_compilation.core$dispatcher}}。

我推测问题可能是由于 {{defmulti}} 宏未设置 {{:name}} 元数据,或者没有正确地将 {{:name}} 元数据传递给编译器。

4 个答案

0
_由: alexmiller_ 发布的评论

所以如果我们深入到细节,这是很有趣的。从技术上讲,在异常发生的点,defmulti 并不在堆栈上(那是调度函数,它已经完成),但在 defmethod 上。

defmethods 实际上定义为 fn's,并且通常被视为匿名函数,尽管实际上可以独立命名它们


user=> (defmulti dispatcher (fn [item] (:type item)))
#'user/dispatcher
user=> (defmethod dispatcher "cat" cat-method
  [{:keys [lives]}]
  (/ lives 0))
#object[clojure.lang.MultiFn 0x6e1d4137 "clojure.lang.MultiFn@6e1d4137"]
用户=> (dispatcher {:type "猫" :lives 9})
ArithmeticException 除以零  clojure.lang.Numbers.divide (Numbers.java:163)
用户=> (pst *e 5)
ArithmeticException 除以零
    clojure.lang.Numbers.divide (Numbers.java:163)
    clojure.lang.Numbers.divide (Numbers.java:3813)
    user/eval155/cat-method--157 (NO_SOURCE_FILE:11)         ;; <== cat-method
    clojure.lang.MultiFn.invoke (MultiFn.java:229)
    user/eval161 (NO_SOURCE_FILE:12)


我认为最好的做法是让defmethod函数默认使用defmulti函数的名称(如果没有指定名称)。
0

评论者:alexmiller

CLJ-2212有关联

0

评论者:marc

哦,很有趣。

在这个例子中,通过将某种字符串形式的调度值附加到标识多方法(调度器)的符号上,将是一个很好的默认值。

因此,您可能会有以下函数名称:
dispatcher-defaultdispatcher-cat等。

我假设您还可能需要在结尾处添加一些额外的唯一后缀。

0
...