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 的,通常被视为匿名函数,尽管实际上有可能独立地为它们命名。


用户=> (defmulti dispatcher (fn [item] (:type item)))
'user/dispatcher
用户=> (defmethod dispatcher "cat" cat-method
         [{:keys [lives]}]
         (/ lives 0))
'object[clojure.lang.MultiFn 0x6e1d4137 "clojure.lang.MultiFn@6e1d4137"]
用户=> (dispatcher {:type "cat" :lives 9})
算术异常 除以零  clojure.lang.Numbers.divide (Numbers.java:163)
用户=> (pst *e 5)
算术异常 除以零
    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
by

由:alexmiller 评论

CLJ-2212 是相关的

0
by

由:marc 评论

哦,有趣。

在这种情况下标识多态方法(dispatcher)的符号(在本例中为一些分派值的字符串表示)在这里将是一个很好的默认值。

所以您可能会有如下命名的函数:
dispatcher-default, dispatcher-cat 等。

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

0
by
参考:https://clojure.atlassian.net/browse/CLJ-2419(由 marc 报告)
...