请在 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

对于映射也会有同样的问题,所以 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集合中正好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
by

评论者:alexmiller

我认为应在https://clojure.org/data_structures上详细介绍有关hash的详细信息,而不是在文档字符串中。尽管hash的文档字符串可能需要更新,并指向最新的网站。

0
by

评论者:wagjo

尽管从1.5版开始这是一个破坏性的更改,但在更改日志中应该提及。仍然令我困扰的是,在c.c /=支持这些情况时,而c.c / hash不支持。如果支持c.c / hash代价昂贵,在类似情况下不更好吗?这将消除如下意外的出现

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

0
by

评论者:alexmiller

我不确定如果不保证不可变更改,它是否是一个“破坏性的”更改。 :) 但我理解你的观点。

我认为不支持Clojure和Java集合的=是不切实际的——这看起来很重要和有用。如果这样做毫无代价,我将能够断言,如果没有equiv=true,则hasheq是相同的。

我不认为在票据中提到的示例是人们可能真正遇到的实际问题。hasheq的主要用户是hash map和hash set。因此,为了显现,你需要将Clojure和Java集合的混合放入其中,特别是将视为相等的集合的混合。

仍在考虑。

0
by

评论者:wagjo

为造成打扰道歉,可能还有一个选择,即不要在hasheq中回退到hashCode,而是对请求非值时的hasheq抛出异常。这将导致哈希类型更清晰地区分。当然,这会阻止在hash-set中放入非值。

0

评论者:alexmiller

虽然有简单的"值存在性"检查,但是吗?

0

评论者:jafingerhut

一个想法,或许有其价值:在Util.hasheq方法中添加一个对java.util.Collection实例的测试,而不是为Set、List和Map分别进行三个独立的测试。这并不包括Map.Entry。

0

评论者:alexmiller

Map也没有扩展Collection。

...