请分享您的想法,参加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
by

评论者:alexmiller

由于集合容器(set)的性能提升,我认为我们实际上可以在一些可能之前没有涉及的地方进行集合的检查。所以,用新视角来审视它是值得的。

0
by

评论者:jawolfe

2009年,我向集合函数提交了一个补丁,其中包含显式的 set? 检查,Rich的回答是:“这些函数恰好在第二个参数不是集合时工作是一个实现上的瑕疵,而不是接口的承诺,因此我不支持set? 测试或其他对该行为的任何适应。”但不知道这还是否准确。

0
by

评论由:jafingerhut

如果您需要一个与clojure.set函数行为相同且进行您提供的参数的运行时类型检查的现成的兼容性替换,而如果错误类型则抛出异常(例如,对于并集、交集、差集、子集?和超集?不是集合),请考虑使用fungible库:https://github.com/jafingerhut/funjible

0
by
参考: https://clojure.atlassian.net/browse/CLJ-1682 (由 vhouseman 报告)
...