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

欢迎!请查看关于页面以了解更多关于它是如何工作的信息。

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,Compiler.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报告)
...