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

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

+18
Java 互操作

问题

Clojure 调用 Java 可变参数方法需要为最后一个参数创建一个对象数组。这是互操作时常见的混淆来源。

例如,尝试调用 java.util.Collections.addAll(Collection c, T... elements)

user=> (Collections/addAll [] (object-array 0)) false user=> (Collections/addAll []) IllegalArgumentException No matching method: addAll clojure.lang.Compiler$StaticMethodExpr.<init> (Compiler.java:1401)

方法类提供了一个 {{isVarArg()}} 方法,这个方法可以用来通知编译器以不同的方式处理。

来自 http://groups.google.com/group/clojure/browse_thread/thread/7d0d6cb32656a621

最新补丁已移除,因为不完整且目标不明确

Java 中的可变参数

如目前所述,此票据的范围仅限于省略可变参数,但这只是 Clojure 处理可变参数与 Java 不同的一种情况。为了完整性,这里简要概述了 Java 如何处理可变参数方法,这可能会为Clojure如何以不同的方式做事并确定此票据的目标提供讨论依据。

给定的以下设置

`
public class VarArgs {

public static class SingleVarargMethod {
    public static void m(String arg1, String... args) {}
}

public static class MultipleVarargMethods {
    public static void m(String... args) {}
    public static void m(String arg1) {}
    public static void m(String arg1, String... args) {}
}

}
`

|Java|可能的 Clojure 等价物? |注释|
| :-- | :-- | :-- | :-- |
|{{VarArgs.SingleVarargMethod.m("a");}} | {{(SingleVarargMethod/m "a")}} | |
|{{VarArgs.SingleVarargMethod.m("a", "b");}} | {{(SingleVarargMethod/m "a" "b")}} | |
|{{VarArgs.SingleVarargMethod.m("a", "b", "c");}} | {{(SingleVarargMethod/m "a" "b" "c")}} | |
|{{VarArgs.SingleVarargMethod.m("a", new String[]{"b", "c"});}} | {{(SingleVarargMethod/m "a" (object-array ["b" "c"]))}} | |
|{{VarArgs.MultipleVarargMethods.m();}} | {{(MultipleVarargMethods/m)}} | |
|{{VarArgs.MultipleVarargMethods.m((String) null);}} | {{(MultipleVarargMethods/m nil)}} |使用类型提示来消除歧义?|
|{{VarArgs.MultipleVarargMethods.m((String[]) null);}} | {{(MultipleVarargMethods/m nil)}} |使用类型提示来消除歧义? |
|{{VarArgs.MultipleVarargMethods.m("a", null);}} | {{(MultipleVarargMethods/m "a" nil)}} | |
|{{VarArgs.MultipleVarargMethods.m("a", new String[]{});}} | {{(MultipleVarargMethods/m "a" (object-array 0))}} | |
|{{VarArgs.MultipleVarargMethods.m(new String[]{"a"});}} | {{(MultipleVarargMethods/m (object-array ["a"]))}} | |
|{{VarArgs.MultipleVarargMethods.m("a", new String[]{"b", "c"});}} | {{(MultipleVarargMethods/m "a" (object-array ["b" "c"]))}} | |

13 个回答

0
0

评论由:ataggart

补丁添加了对varargs的支持。该补丁在CLJ-445补丁的基础上构建。

0

评论由:ataggart

补丁已更新到当前CLJ-445补丁。

0

评论由:klauern

此工单是否暂停?我发现我经常输入 {{(.someCall arg1 arg2 (into-array SomeType nil))}} 来确保调用正确的方法。这个工单似乎可以解决我经常使用的多余 {{into-array}} 参数。

0

评论由:jafingerhut

于2012年10月29日上传的fixbug445.diff由Alexander Taggart于2010年10月23日编写。我只是将它从旧的Assembla工单跟踪系统复制到这里,以便更容易访问。不出所料,它不能干净地应用到最新的master上。我不知道更新它需要多少努力,但根据'patch',只有几个片段无法干净地应用。请参阅此处JIRA工作流程页面上的“更新过时的补丁”部分:http://dev.clojure.org/display/design/JIRA workflow

0

评论由:jafingerhut

唉。删除了附件,因为它是为CLJ-445的,或者至少是那么命名的。CLJ-445确实有一个漫长的注释历史,因此如果您或多个补丁解决了这个问题,您可以通过阅读那里的讨论来查看历史记录。

我没有听说过有“挂起”状态的工单,除了Rich Hickey在评论中明确表示想要等待一段时间才进行修改的少数几个工单。只是有贡献者选择的要工作的工单和筛选者选择的要筛选的工单。

0

评论人:alexmiller

我非常希望看到对这个工单更新的补丁,该补丁专门解决了参数变量问题,而不是基于其他提到的工单和补丁(优先级较低)来构建。

0

评论人:ragge

我试了一下,已经附上一个初始补丁,其中一些部分我不是很确定/高兴,所以欢迎反馈。

这个补丁采取以下方法

  1. 教给{{Reflector/getMethods}}如何找到匹配的参数变量方法。除了当前约束外,一个方法还可以匹配,如果它是一个参数变量方法,并且方法的数量比请求的数量多一个。这意味着它是一个我们可以调用的参数变量方法,但用户没有提供参数变量参数。
  2. 我们在{{MethodExpr/emitTypedArgs}}中处理了方法调用时包含比提供的参数多的情况。唯一应该发生这种情况的情况是它是一个参数变量方法,并且最后一个参数没有提供。在这种情况下,我们在堆栈上推送一个新的空对象数组。

我对我的实现的第二部分不是很确定。这可能会在未来产生一些难以理解的错误。一个选择是更加防御性,并确保它确实是最后一个参数,例如,或者传递{{Method}}对象(或参数变量标志)以让我们真正了解我们可以预期的内容和需要做什么。

0

评论人:ragge

我意识到我的补丁缺失了两个重要案例;在Reflector中的接口处理和多个匹配方法的处理。我也会查看这些案例,但仍然希望对{{MethodExpr/emitTypedArgs}}中的方法给予反馈。

0

评论人:alexmiller

我赞成使用isVarArg()显式处理此情况,而不是猜测我们是否处于这种情况。我们应该检查调用带有不足/过多参数的参数变量方法的操作(并在需要的地方添加测试),并再次检查非参数变量情况是否未更改行为。

此外,请注意,作为一般原则,现有AOT编译的代码可能依赖于调用公共Reflector方法,所以如果您更改公共Reflector方法的签名,您应该保留具有旧参数数量的版本,以便向后兼容具有一些默认行为。

0

评论者:gshayban

编译器实现的任何额外逻辑都需要区分

`

public static class MultipleVarargMethods {
    public static void m(String... args) {}
    public static void m(String arg1, String... args) {}
}

`

我认为没有打破代码的情况下,这通常是不可能的。

与其省略可变参数,不如在没有繁琐的数组构造的情况下处理它们。另一种方法是引入必须选择加入的新显式糖

(Whatever/varargs a b c ... x y z)

其中...或类似项将由编译器中的StaticMethodExpr或InstanceMethodExpr理解,并且可以指定类型提示以解决歧义。这不会是一个破坏性更改。

0

评论者:pbwolf

如果javac可以在调用者不带"..."分区的帮助下区分方法,那么Clojure也应该如此。(但在特定的"MultipleVarargMethods"类中,javac无法区分)

`
public class MultipleVarargMethods {

public static void m(String... args) {}
public static void m(String arg1, String... args) {}
public static void main(String [] args) {
    m("bankruptcy");
    m("bankruptcy","in","progress");
}

}

MultipleVarargMethods.java:5: 错误:对m的引用模糊不清

    m("bankruptcy");
    ^

MultipleVarargMethods中的方法m(String...)和MultipleVarargMethods中的方法m(String,String...)都匹配
MultipleVarargMethods.java:6: 错误:对m的引用模糊不清

    m("bankruptcy","in","progress");
    ^

MultipleVarargMethods中的方法m(String...)和MultipleVarargMethods中的方法m(String,String...)都匹配
2个错误
`

)

0
...