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
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分支。我不知道这需要多少努力来更新,但根据“更新过时补丁”部分,只有几个块根据‘补丁’无法应用干净。请参阅此处JIRA工作流程页面上的“更新过时补丁”部分: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
by

评论作者:alexmiller

我赞成使用isVarArg()来显式处理这种情况,而不是猜测我们是否处于这种情况。我们应该检查调用具有过多参数、过少参数等的var args方法的行为(并在似乎需要的地方添加测试)。还应该仔细检查非vararg情况的行为是否未被改变。

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

0
by

评论者:gshayban

编译器实现的任何额外逻辑都必须能够区分

`

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

`

我认为这是不可能通用的,否则会破坏代码。

与其省略varargs,不如在不必进行繁琐的数组构造的情况下处理它们。一个替代方法是引入新的显式糖语法,但需要您同意

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

其中 ... 或类似的内容将被编译器的StaticMethodExpr或InstanceMethodExpr理解,并且可以类型提示以消除歧义。这将不会是一个破坏性的更改。

0
by

评论者:pbwolf

if 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...)和m(String,String...)匹配。
MultipleVarargMethods.java:6: 错误:m引用不明确

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

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

)

0
by
...