2024 年 Clojure 发展状况调查中分享您的想法!

欢迎!请参阅关于页面获取有关此工作方式的一些更多信息。

0
协议

实现重载参数数量协议方法的所需形式在 "extend-**" 宏和 "defrecord" 之间存在不一致性。

"extend" 宏系列要求重载方法定义遵循 defn 形式

(方法 ([arg1] ...) ([arg1 arg2] ...))

然而,"defrecord" 要求单独定义实现

(方法 [arg1] ...) (方法 [arg1 arg2] ...)

此外,如果您出错,错误模式并不友好。

如果您在 "extend-**" 中使用 "defrecord" 形式,它将成功评估,但后续定义会静默地覆盖词法上之前定义的内容。

如果您在 "defrecord" 中使用 "extend-**" 形式,它会在方法的主体上给出一个关于“不支持绑定形式”的神秘错误。

这不是与 CLJ-1056 相同的问题:那与声明协议的语法有关,这个问题是与实现协议的语法有关。

`

(defprotocol MyProtocol
(mymethod

[this arg]
[this arg optional-arg]))

(extend-protocol MyProtocol
Object
(mymethod

([this arg] :one-arg)
([this arg optional-arg] :two-args)))

;; 错误!崩溃并报错 "Unsupported binding form: :one-arg"
(defrecord MyRecord []
MyProtocol
(mymethod

([this arg] :one-arg)
([this arg optional-arg] :two-args)))

;; 工作正常...
(defrecord MyRecord []
MyProtocol
(mymethod [this arg] :one-arg)
(mymethod [this arg optional-arg] :two-args))

;; 评估...
(extend-protocol MyProtocol
Object
(mymethod [this arg] :one-arg)
(mymethod [this arg optional-arg] :two-args))

;; 但然后... 出错! "参数数量不正确"
(mymethod :obj :arg)

;; 两个参数版本是可以调用的...
(mymethod :obj :arg1 :arg2)
`

4 答案

0
由:pparkkin_ 发表评论

附上了此问题的补丁。

对于 defrecord,我检查了用于定义方法的样式,如果使用了新样式,则将其转换为原始样式。对于检查,我做了我认为 defn 会做的事情,即 {{(vector? (first fdecl))}}。

对于 extend-*,我跳过了检查,只是将一切都转换为相同的格式。

为两者都包含了测试。

所有测试都通过。
0

评论者:richhickey

提案是什么?

0
_评论者:tsachev_

这也让我受到影响。

我通过为多参数方法的协议使用 {{extend}} 来解决这个问题
例如,以上示例

(extend Object
  MyProtocol
  {:mymethod (fn ([^Object this arg] :one-arg)
                 ([^Object this arg optional-arg] :two-args))})
0
参考: https://clojure.atlassian.net/browse/CLJ-825(由 alex+import 报告)
...