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

欢迎!有关此功能如何工作的更多信息,请参阅关于页面。

0投票
Clojure
clojure.set/intersection,按照意图和文档说明,应该是在两个集合之间进行操作。然而,有时候它允许(并且返回正确的操作结果)非集合参数。这可能会让人误以为非集合参数是可以使用的。

以下是一个关于Set与KeySeq的示例
如果存在交集,您将得到一个结果。这可能会使编写此代码的人认为这是可以的,或者没有注意到他们使用了一个不兼容的数据类型。然而,一旦交集为空,就会发生相应的类型错误,尽管这是由于clojure.core/disj的第一个参数应该是集合而意外发生的。


user=> (require '[clojure.set :refer [intersection]])
nil
user=> (intersection #{:key_1 :key_2} (keys {:key_1 "na"}))   ;这可以工作,但不应该
(:key_1)
user=> (intersection #{:key_1 :key_2} (keys {:key_3 "na"}))   ;这失败了,因为intersection假设第二个参数是一个集合
ClassCastException clojure.lang.APersistentMap$KeySeq不能转换到clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)

(disj (keys {:key_1 "na"}) #{:key_1 :key_2})   ;intersection所做的假设
ClassCastException clojure.lang.APersistentMap$KeySeq不能转换到clojure.lang.IPersistentSet  clojure.core/disj (core.clj:1449)


对一个明显是为特定类型设计的库执行类型安全检查似乎很负责任。它可以防止 bug 代码被无意中接受为正确,直到正确的数据出现并踩中陷阱。

5 答案

0投票

评论者:jafingerhut

CLJ-810与此相似,但它针对的是clojure.set/difference函数。那次提交被拒绝,评论是 "如果没有传入集合,set/difference的行为没有文档说明。"我不知道核心团队将如何评估这次提交,但想提供一个历史背景。

Dynalint(链接:1)和我认为可能还可以使用Dire(链接:2)为核心函数添加动态参数检查。

(链接:1) https://github.com/frenchy64/dynalint
(链接:2) https://github.com/MichaelDrogalis/dire

0投票

由 alexmiller 发表的评论:

由于现在 set 的效率更高,我认为我们实际上可以在一些以前可能没有检查集合的地方添加对集合的检查。因此,用新的眼光重新审视它是有价值的。

0投票

由 jawolfe 发表的评论:

在2009年,我向集合函数提交了一个带有显式 set? 检查的补丁,Rich 的回复是:“这些函数在第二个参数不是集合时恰好能工作,这只是一种实现上的特性,而不是界面的承诺,所以我反对进行 set? 测试或任何对此类的妥协。”不过,不清楚这个说法是否仍然准确。

0投票

评论者:jafingerhut

如果您需要一个与 clojure.set 函数在行为上完全相同,但执行运行时类型检查您提供的参数,并在它们类型不正确时抛出异常(例如,并集、交集、差集、子集和超集不是集合)的现成兼容替代品,请考虑使用 fungible 库: https://github.com/jafingerhut/funjible

0投票
参考: https://clojure.atlassian.net/browse/CLJ-1682 (由 vhouseman 提出)
...