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

欢迎!请查阅关于页面了解此处的更多信息。

0
Clojure

有几个工单涉及的问题是,当{{clojure.set}}中的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处理可能是一个可行的方案,但同样,如果函数同时接收和返回集合,则可能会破坏data.diff。
1. 保持当前状态,我们将继续让新旧Clojure程序员感到惊讶。

这个问题是问题的证据
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_

我会在这里尝试第一步(最小化)。由于集合函数的文档字符串以 "返回一个集合" 开头,可以合理地期望它们总是返回一个集合。

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

我期望的是,在带有断言编译的代码中会显示出来后置条件错误。

具体来说,我认为在集合函数上封装 `{:post [(set? %)]}` 后置条件是有意义的。它不解决强制转换问题,并且避免了关于有效参数的讨论,它只是根据文档对返回值设置限制。

鉴于文档字符串中的内容,我认为没有代码依赖于集合函数返回除了集合以外的任何内容。

后置条件的性能影响仅在启用断言时才会存在。

我意识到这并没有解决所有提到的问题,但这或许是一个向前迈进的方法。

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