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 并通常被视为匿名函数,尽管实际上可以独立地对它们进行命名


user=> (defmulti dispatcher (fn [item] (:type item)))
#'user/dispatcher
user=> (defmethod dispatcher "cat" cat-method
         [{:keys [lives]}]
         (/ lives 0))
对象[clojure.lang.MultiFn 0x6e1d4137 "clojure.lang.MultiFn@6e1d4137"]
user=> (dispatcher {:type "cat" :lives 9})
算术异常 除以零  clojure.lang.Numbers.divide (Numbers.java:163)
user=> (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投票

评论者:alexmiller

CLJ-2212相关

0投票

评论者:marc

哦,有趣。

在这种情况下识别多方法(dispatcher)的符号,附加某种字符串形式的分发值,将是一个非常好的默认值。

您可能有以下函数的名称
dispatcher-default, dispatcher-cat等。

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

0投票
...