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假设第二个参数是Set
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)


在一个旨在特定类型的库上强制类型安全似乎是一个负责任的做法。它防止了错误代码在不知情的情况下被视为正确,直到正确的数据出现以踩中陷阱。

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 报告)
...