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

欢迎!请查看关于 页面以获取有关此工作如何进行的更多信息。

0
Collections

c.c/hash 总是使用 hashCode 对于 Java 集合,这与使用 Murmur3 的 Clojure 集合不兼容。

user=> (== (hash (java.util.ArrayList. [1 2 3])) (hash [1 2 3])) false user=> (= (java.util.ArrayList. [1 2 3]) [1 2 3]) true

修复此问题的一种方法是向 Util/hasheq 中添加针对 java.util.Collections 的特殊案例,就像它对字符串所做的那样。

有关此主题的 Clojure 小组讨论链接:https://groups.google.com/forum/#!topic/clojure/dQhdwZsyIEw

43 答案

0

评论者:wagjo

对于映射来说也是同样的问题,因此 hasheq 应该为 java.util.Map 也有一个特殊案例。

0

评论者:wagjo

添加了修复 j.u. Map、Set 和 List 的补丁。

0

评论者:jafingerhut

添加补丁 clj-1372-2.diff,该补丁与 Jozef Wagner 的 clj-1372.diff 相同,但它还添加了一些在更改后失败、在更改后通过的测试。

0

评论由:alexmiller 发布

我认为equiv/hasheq协议的范围比这更窄,并且仅在两个集合都是IPersistentCollection时才适用。换句话说,我认为这不需要也不要求。

请注意,这里的Java .equals/.hashCode 协议维护的——这些集合将作为.equals()比较,并且具有相同的.hasheq()。

0

评论者:wagjo

如果没有补丁,以下语句是不正确的:“如果两个对象在使用c.c/=相等时,c.c/hash返回的哈希值也相同”。我们可以说,这只有在两个对象都是'clojure'对象时才正确,但这与clojure的互操作性原则相悖(互操作性简单、快速、无惊喜)。

0

评论者:wagjo

此错误的体现

user=> (assoc (hash-map [1 2 3] :foo) (java.util.ArrayList. [1 2 3]) :bar) {[1 2 3] :bar, [1 2 3] :foo} user=> (get (hash-map [1 2 3] :foo) (java.util.ArrayList. [1 2 3])) nil

0

评论由:alexmiller 发布

我同意,这样说是没有问题的。

在hasheq中添加更多分支的确有代价——这些集合检查会影响所有的hasheq。在运行完整的Clojure构建时,我发现以下具有>100个此类发生位置的类集(请注意,这些Java集合中恰好0个存在于Clojure构建本身中)

clojure.lang.Var 107001502 java.lang.Class 2651389 java.lang.Character 2076322 java.util.UUID 435235 java.util.Date 430956 clojure.lang.Compiler$LocalBinding 116830 java.lang.Boolean 112361 java.util.regex.Pattern 325

我们将在每个hasheq的路径中添加4个额外的instanceof检查。这也可能会爆掉任何JVM内联。

Rich 说“对于非值类型的hasheq/equiv,任何赌注都应该解除”,显然Java 集合也属于“非值”类别。

0

评论者:jafingerhut

是否可以考虑文档补丁?比如说一个修改clojure.core/hash文档的补丁,包含表明它只保证与clojure.core/=对于不可变值的一致性的短语?甚至可以提到浮点数也不支持,详见CLJ-1036。

0

评论由:alexmiller 发布

我认为最好在 https://clojure.org/data_structures 上编写有关哈希的详细文档,而不是在文档字符串中。尽管哈希的文档字符串可能需要更新,并在最新更改后指向网站。

0

评论者:wagjo

尽管这是一个从 1.5 开始的重大变更,但它应该在变更日志中提 mention。仍然让我烦恼的是,在这种情况下支持 c.c/=,但 c.c/hash 并不支持。如果支持 c.c/hash 比较昂贵,那么在这种情况下不支持 c.c/= 好不好?这将消除类似的惊喜:

user=> (apply distinct? (hash-set [1 2 3] (java.util.Collections/unmodifiableList [1 2 3]))) false

0

评论由:alexmiller 发布

我不确定如果不考虑为保证的变化的话,这算不算一个"重大变更"。 :) 但我明白了你的观点。

我认为在 Clojure 和 Java 集合中放弃 = 的支持是不可行的 - 这似乎很重要且非常有用。如果这样做的代价很低,我愿意断言,如果 equiv=true,那么 hasheq 就是相同的。

我不认为这个工单上列出的问题示例实际上是人们可能会遇到的真正的困难。hasheq 的主要用户是哈希映射和哈希集。所以如果想出现这种情况,你需要将 Clojure 和 Java 集合的混合体放入其中一个中,特别是比较为相等的集合混合体。

仍在考虑中。

0

评论者:wagjo

抱歉发这么多,但可能还有一个选择,即不在 hasheq 中回退到 hashCode,而是在请求非值时抛出异常。这将导致对哈希类型的更清晰分离。当然,这将阻止将非值放入 hash-set。

0

评论由:alexmiller 发布

但是"valueness"没有简单的检查吗?

0

评论者:jafingerhut

一个想法,其价值如何:在Util.hasheq方法中增加一个java.util.Collection实例的测试,而不是为Set、List和Map分别进行3个独立的测试。它没有涵盖Map.Entry。

0

评论由:alexmiller 发布

Map也没有扩展Collection。

...