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

欢迎!有关如何操作,请参阅关于页面以获取更多信息。

0
Collections

c.c/hash 对于 Java 集合始终使用 hashCode,这在与使用 Murmur3 的 Clojure 集合进行比较时是不兼容的。

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

解决此问题的一种方法是在 Util/hasheq 中为 java.util.Collections 添加一个特殊案例,就像现在为 Strings 那样。

有关此主题在 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()比较,并且确实具有相同的.hashCode().

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集合 - 这种情况本身就不存在于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的non-values应该放弃所有赌注" WHERE Java collections显然是非值的一部分。

0

由:jafingerhut 评论

是否应考虑文档补丁?比如说,对clojure.core/hash的文档进行修改,以包含仅对不可变值与clojure.core/=保持一致性的短语?甚至可以提及浮点数也不行:见CLJ-1036

0

由 alexmiller 发表评论

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

0

由:wagjo 评论

尽管如此,这是从1.5版本开始的重大更改,应该在变更日志中提到。仍然让我感到不安的是,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,而是在请求非值时的hasheq中抛出异常。这将导致哈希类型的更清晰分离。当然,它会阻止非值放入哈希集中。

0
by

由 alexmiller 发表评论

但是没有简单的“值存在性”检查吗?

0
by

由:jafingerhut 评论

一个想法,尽管可能价值不大:在Util.hasheq方法中添加一个针对java.util.Collection实例的测试,而不是为Set、List和Map分别添加3个单独的测试。但这并不涵盖Map.Entry。

0
by

由 alexmiller 发表评论

Map也不会扩展Collection。

...