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

对于映射也存在相同的问题,因此 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返回的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的主要用户是哈希图和哈希集。所以,要显现出来,你需要把Clojure和Java集合混合在一起,特别是比较相等的集合。

仍在思考中。

0

评论者:wagjo

抱歉打扰了,但可能还有一个选项,不是在hasheq中回退到hashCode,而是在hasheq请求非值时抛出异常。这将会带来更清晰的散列类型分离。当然,这将防止非值放入哈希集中。

0

评论者:alexmiller

不过,没有简单的方法来检查“值的”。

0
by

评论者:jafingerhut

一个可能有价值的想法:在Util.hasheq方法中添加一个java.util.Collection实例的测试,而不是为Set、List和Map单独进行3个测试。它不包含Map.Entry。

0
by

评论者:alexmiller

Map也没有扩展Collection。

...