2024 年 Clojure 状态调查!中分享您的想法。

欢迎!有关如何操作的更多信息,请参阅关于页面。

0 投票
Java 互操作

这是在 Java 1.8(Oracle 或 Open JDK)上

`
weird-abs.core=> (Math/abs -10000000000000)
10000000000000
weird-abs.core=> (def a -10000000000000)

'weird-abs.core/a

weird-abs.core=> (Math/abs a)
1316134912
`

在 Java 1.7 中,返回预期的结果(10000000000000)。

原因:看起来调用了 Math.abs(int)。反射器考虑了 int 和 long 版本,但 Java 1.7 和 1.8 以不同的顺序返回这些签名,并且找到的第一个被选中。

解决方案:使用提示或强制转换为通知反射器选择哪一个。

6 答案

0 投票

评论者:alexmiller

在第一种情况下,-10000000000000 是 long 类型,编译器明确找到 Math.abs(long)。

在第二种情况下,a 是 Object 类型,所有 abs 签名都被考虑(这是在 Reflector.invokeMatchingMethod 中)。在 Java 1.7 和 1.8 中,long 和 int 签名都被找到“一致”。

在 Java 1.7 中,long 版本首先找到并被视为匹配项,然后检查 int,Compileer.subsumes((link: int), (link: long)) 返回 false,导致 long 方法被保持为匹配项。

在 Java 1.8 中,int 版本首先找到并被视为匹配项,然后检查 long,Compiler.subsumes((link: long), (link: int)) 返回 false,导致 int 方法被保持为匹配项。

这两个在两个 JDK 上都返回 false

(Compiler/subsumes (into-array [Long/TYPE]) (into-array [Integer/TYPE])) (Compiler/subsumes (into-array [Integer/TYPE]) (into-array [Long/TYPE]))

所以真正的区别只是考虑的顺序,这是 JDK 相关的。

考虑的签名可以通过某些规范方式进行排序,以使此行为一致,或者也许可以通过某种方式表达对两个签名之间的偏好。

无论如何,通过提示或强制类型转换来消除这里的反射可以解决问题 - 我认为,在这种情况下,Java 7得到的正确结果更多的是运气而非意图。

0 投票

评论由:bronsa发表

在我看来,clojure的反射器在有多种重载可用时随机选择一个的行为既不直观又不可取。

我认为唯一合理的做法是
- 如果可能,选择最具体的类型(例如,如果可用的是(链接:Object, CharSequence, String)而反射类型是StringBuffer,我们使用CharSequence而不是Object)。
- 如果可能,选择最宽的原生类型(例如,在这种情况下我们会使用long而不是int)。
- 如果冲突无法解决,则抛出More than one matching method found异常(这已经在某些情况下发生)。

(我仍然因为之前阅读/修补了那个复杂得令人害怕的东西 —— Reflector.java和Compiler.java的反射部分而感到恐惧,所以我提出这个建议,并没有打算自己亲自来做这项工作 :))

0 投票

评论者:alexmiller

我认为subsumes检查实际上已经在尝试做你的选项#1了 - 这是一个两个情况中的参数类型之间没有层次关系的例子。可能选项#2更有意义 - 表达一种偏好,尽管在“最宽”没有意义的某些情况下,所以不确定这个一般形式是什么。

0 投票

评论由:bronsa发表

为了澄清,那不是一个不同选项的列表,而是一个要采取的步骤列表。
即,如果可能从层次结构中选择最具体的类型,就那样做;否则如果类型是原生的,选择最宽的类型;否则失败。

0 投票

评论由:jafingerhut发表

可能和CLJ-1212一样,或者至少有一些共同之处。

0 投票
参考: https://clojure.atlassian.net/browse/CLJ-1921(由alexmiller报告)
...