请在 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 的特殊案例,就像现在对 Strings 那样。

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

43 答案

0

评论者:wagjo

对于 maps,也存在相同的问题,因此 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'对象,但这与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构建,我发现以下类中出现了这种情况(注意,这些中没有一个是在Clojure构建本身中存在的Java集合)

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的主要用户是哈希映射和哈希集合。因此,为了显示效果,你必须将 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。

...