2024 Clojure 状态调查! 中分享您的想法。

欢迎!请查看 关于 页面以获取更多关于这个工作方式的信息。

0
协议

实现重载算术量协议方法的格式在不同的 "extend-" 宏和 "defrecord" 之间不一致。

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

(method ([arg1] ...) ([arg1 arg2] ...))

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

(method [arg1] ...) (method [arg1 arg2] ...)

此外,错误模式如果你搞错了是无用的。

如果你使用 "defrecord" 形式与 "extend-",它将成功评估,但后来的定义静默地覆盖词法先前的定义。

如果你使用 "extend-" 形式与 "defrecord",它会在方法体上出现关于 "不支持的绑定形式" 的神秘错误。

这不是与 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)))

;; 错误!会崩溃:"不支持的绑定形式::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}} 方法解决了这个问题,用于具有多 arity 方法的协议
例如:

(扩展 Object
  MyProtocol
  {:mymethod (fn ([^Object this arg] :single-argument)
                 ([^Object this arg optional-arg] :two-arguments)))
0
参考:https://clojure.atlassian.net/browse/CLJ-825(由 alex+import 报告)
...