请在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)

Method类提供了一个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

评论由:importer 发布

来源于 http://www.assembla.com/spaces/clojure/tickets/440

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 工单跟踪系统中将其复制到此处以便于访问。不出所料,它无法干净地应用于最新版本的主分支。我不知道更新它需要多少工作量,但只有几个块在 'patch' 中无法干净地应用。请参阅这里的“更新陈旧补丁”部分:http://dev.clojure.org/display/design/JIRA workflow

0

评论由:jafingerhut 发布

哦,删除了附件,因为它是为 CLJ-445 而设计和命名的。CLJ-445 确实有长长的评论历史,所以如果您或多个补丁解决了这个问题,那么您可以通过阅读那里的讨论来查看历史。

我未听说过关于工单的“挂起”状态,除了Rich Hickey在一两条评论中明确表示他想要等待一段时间再进行修改的情况。只是有些工单是由贡献者选择工作的,有些则是由审核者选择审核的。

0

评论人:alexmiller

我非常希望看到针对该工单的更新补丁,专门解决varargs问题,而不依赖于其他提到的工单和补丁(该补丁优先级较低)。

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
参考: https://clojure.atlassian.net/browse/CLJ-440(由ataggart报告)
...