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

欢迎!请访问关于页面,了解更多关于如何使用本平台的信息。

0
Clojure

有多个问题票与 {{clojure.set}} 中的集合函数在传递非集合参数时行为不当的情况有关。

这些问题包括 CLJ-810、CLJ-1087、CLJ-1682 和 CLJ-1954

受影响的功能有:

  1. difference
  2. intersection
  3. union
  4. subset?
  5. superset?

因为这些函数在传递非集合参数时会产生意外结果。

问题
如上述问题所述,当前这些函数的实现导致在调用非集合输入时产生混淆和错误的结果。用户未得到任何警告或错误指示。

可能的解决方案
1. 在这些函数的参数上的 {{set}} 添加强制转换
1. 当参数不是集合时抛出异常
1. 使用 clojure.spec 处理这个问题
1. 保持原样

权衡
1. 根据 CLJ-2362,将 {{set}} 调用接近于空操作,这种强制转换不应引起太大的性能损失。有人认为代码甚至可能更快,因为可以给出类型提示,编译器/jit 可能会做出更好的选择。对于常见的错误(传递向量/列表而不是集合),应该保持向后兼容
1. 当参数不是集合时抛出异常将破坏今天运行正常(尽管是偶然)的程序,例如 data.diff。
1. 使用 clojure.spec 来处理这个问题似乎是一个可行的选项,但再次,如果函数被 spec 为同时接收和返回集合,这将破坏 data.diff。
1. 保持不变,我们将继续让新旧 Clojurists 都感到惊讶。

证明这个问题是存在的证据
1. 提到的这些问题似乎表明,人们经常会偶然发现并提交问题
1. https://docs.clojure.org/clojure.set/superset_q#example-5b5acd38e4b00ac801ed9e39

5 个答案

0

评论者:alexmiller

在考虑此问题之前,需要…

  • 一个良好的问题陈述
  • 评估现有代码在非集合对象上调用这些函数的情况
  • 一个表格,列出了可供选择的方案及其权衡。推测性的方案包括:增加规范、增加验证检查、增加强制类型转换等。权衡可能包括对现有调用者(已知或未知)的影响、性能等。

要作出的决定

  • 现有的调用(具有非集合的输入)是有效的还是无效的?
  • 函数应该做出哪些更改?

在这些问题得到解决之前,补丁可能不太有用。

0

由 borkdude 发表评论

Andy Fingerhut 的存储库中有趣的数据,比较了具有预状态的集函数版本的性能

  • (没有强制类型转换)
  • 仪表化集函数

具有预条件的函数比仪表化的函数快得多,但比原始的没慢多少。

https://github.com/jafingerhut/funjible#wait-isnt-this-what-clojurespec-is-for

0

stu 发布了评论

规范测试可以比较输入和输出,而不会破坏任何现有代码。

0
jwr_ 发布评论

我将尝试第一步。由于集函数的doc字符串以 "返回一个集合" 开始,我们可以合理地期望它们始终返回一个集合。

我遇到的特定情况是 `(clojure.set/difference nil #{1})` 返回 nil。nil 出现的原因是由于可选项:执行了集合操作,源数据在映射中是可选的。数据通过了规范验证(因为键是可选的),后来又因为由 set/difference 返回的 nil 而触发了其他验证。我意识到参数不正确,并且我并不一定期望自动强制类型转换。

我所期望的是,在经过断言编译的代码中会出现后条件错误。

具体来说,我认为在集合函数上添加 `{:post [(set? %)]}` 后条件是可以商定的。这并没有解决强制类型转换的问题,也不涉及有效参数的讨论,它只是根据文档对返回值设置了一个限制。

根据 docstrings 的说明,我认为没有代码依赖于集函数返回除了集合以外的东西。

只有在编译时开启断言的情况下,后条件的影响才会出现。

我明白这并没有解决所有提到的问题,但这可能是向前推进的一种方式。

我认为这并不是目前标记的“重大”问题。
0
参考: https://clojure.atlassian.net/browse/CLJ-2433(由 slipset 报告)
...