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 添加一个特例,就像现在为 Strings 设置的那样。

有关此主题的讨论链接: 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 投票
by

评论由: alexmiller 提出

我认为equiv/hasheq合约的范围比这更窄,并且只有当两个集合都是IPersistentCollection时才适用。换句话说,我认为这不是需要的或必须的。

请注意,这里的Java .equals/.hashCode合约**确实**得到维护 - 这些集合将作为.equals()比较,并且确实有相同的.hashCode()。

0 投票
by

评论者:wagjo

如果没有补丁,以下陈述就不成立:"如果两个对象在使用c.c/=时相等,那么它们由c.c/hash返回的哈希是相同的数字"。我们只能说,只有在两个对象都是'clojure'对象时才成立,但这违反了clojures互操作原则(互操作简单、快速、没有惊喜)。

0 投票
by

评论者:wagjo

此错误的体现

用户=> (get (hash-map [1 2 3] :foo) (java.util.ArrayList. [1 2 3])) nil

0 投票
by

评论由: 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 投票
by

评论者:jafingerhut

是否可以将doc补丁考虑在内?比如说,修改clojure.core/hash文档的补丁,添加一个表明它与clojure.core/=对于不可变值保持一致的短语?甚至可以提及Floats也这个问题:参见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,而是在这些情况下抛出异常。这将导致对hash类型的更清晰分离。当然,这将防止非值进入hash-set。

0 投票

评论由: alexmiller 提出

但是没有简单的检查“值”的方法?

0 投票
by

评论者:jafingerhut

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

0 投票
by

评论由: alexmiller 提出

Map 也不继承自 Collection。

...