2024 State of Clojure Survey!中分享您的观点。

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

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)


对于一个显然为特定类型而设计的库,强制类型安全似乎是一件负责任的事情。这可以防止带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 的回答是:“这些函数在第二个参数不是集合时能正常工作仅仅是实现层面的特性,而不是接口的承诺,所以我不支持这种测试或任何其他对此的适应。” 不确定这还是否准确。

0

评论者:jafingerhut

如果你需要一个与 clojure.set 函数行为相同的现成替换品,它们除了在运行时对提供的参数执行类型检查外,如果它们具有错误的类型(例如对于联合、交集、差集、子集? 和超集? 不是集合),则抛出异常,请考虑使用 fungible 库:https://github.com/jafingerhut/funjible

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