2024 年 Clojure 调查问卷 中分享您的想法!

欢迎!请参阅 关于 页面以了解有关该工作的更多信息。

0
Collections

c.c/hash 总是使用 Java 集合的 hashCode,这与使用 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()比较,并且确实有相同的.hashCode()。

0
by

评论由:wagjo 提出

如果没有补丁,以下陈述是不成立的:“如果两个对象通过与c.c/=相等,那么它们通过c.c/hash返回的哈希值是相同的”。我们可以说,只有在两个对象都是'clojure'对象的情况下这才是成立的,但这对clojures互操作原则来说是相反的(互操作简单、快速、没有惊喜)。

0
by

评论由: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
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 提出

一个文档补丁会被考虑吗?例如,修改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。因此,要实现这一点,你需要将这些集合混合起来,尤其是混合集合,以便进行比较。

仍在考虑。

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。

...