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 添加一个特殊案例,就像它现在对 String 所做的那样。

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

43 答案

0

评论者:wagjo

对于 map 也存在同样的问题,因此 hasheq 应该为 java.util.Map 也有一个特殊案例。

0

评论者:wagjo

已添加修正 j.u. Map、Set 和 List 的补丁。

0

评论者:jafingerhut

添加与 Jozef Wagner 的 clj-1372.diff 相同的补丁 clj-1372-2.diff,除了它还添加了一些在没有他的更改的情况下失败的测试,而在有他的更改的情况下通过。

0

评论由:alexmiller 提出

我认为equiv/hasheq的合约范围比这更窄,只适用于两个集合都是IPersistentCollection的情况。换句话说,我觉得这不需要也不想这么做。

请注意,这里的Java .equals/.hashCode合约**确实**保持不变——这些集合将等同于.equals()并且具有相同的.hashCode()。

0

评论者:wagjo

如果没有这个补丁,以下声明是不成立的:"如果两个对象在c.c/=中相等,那么c.c/hash返回的哈希值相同"。我们可以说,这只在两个对象都是'clojure'对象的情况下成立,但这与clojures互操作性原则(互操作性简单,快速,无惊喜)相矛盾。

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的非值应该没有任何条件",而Java集合显然属于"非值"类别。

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的主要使用者是hash map和hash set。因此,要表现出来,你需要在其中放入Clojure和Java集合的混合体之一,特别是混合了比较相等集合的情况。

仍在考虑中。

0

评论者:wagjo

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

0

评论由:alexmiller 提出

但是有没有简单的“有效性”检查?

0

评论者:jafingerhut

一个想法,或许有用:在 Util.hasheq 方法中增加一个 java.util.Collection 的实例测试,而不是对 Set、List 和 Map 进行三个独立的测试。它不覆盖 Map.Entry。

0

评论由:alexmiller 提出

Map 也不扩展 Collection。

...