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所做的。

有关此主题在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构建时,我看到了以下一组类,其中hasheq出现了>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
by

评论者:alexmiller

我认为最好在https://clojure.org/data_structures上提供关于hasheq的详细信息文档,而不是在文档字符串中。虽然关于hasheq的文档字符串可能需要更新,并指向最新的更改后的网站。

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。因此,要出现,你需要在其中放置Clojure和Java集合的混合,特别是相等比较的集合组合。

还在思考这个问题。

0

评论者:wagjo

抱歉重复,但可能还有一个选择,即不在hasheq中出现回退到hashCode的情况,而是在请求非值的hasheq时抛出异常。这将导致hash类型更清晰的分离。当然,这将防止非值放入hash-set。

0

评论者:alexmiller

但是,是否有简单的检查“值有效性”?

0

评论者:jafingerhut

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

0

评论者:alexmiller

Map 也不继承 Collection。

...