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 null)}} | 使用类型提示进行澄清?|
|{{VarArgs.MultipleVarargMethods.m((String[]) null);}} | {{(MultipleVarargMethods/m null)}} | 使用类型提示进行澄清? |
|{{VarArgs.MultipleVarargMethods.m("a", null);}} | {{(MultipleVarargMethods/m "a" null)}} | |
|{{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 在 2010 年10月23日由 Alexander Taggart 编写。我只是将它从旧 Assembla bug 跟踪系统复制到这里,以便更容易访问。并不奇怪,它没有干净地应用于最新的 master。我不知道需要多少努力来更新它,但是在 'patch' 的根据,只有几个块没有被干净地应用。请参阅此处 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}}如何找到匹配的varargs方法。除了当前的约束条件外,一个方法是还可以匹配,如果它是varargs方法,并且方法的参数数量比要求的多一个。这意味着它是一个我们可以调用的varargs方法,但用户没有提供varargs参数。
  2. 在{{MethodExpr/emitTypedArgs}}中,我们处理了方法调用中参数数量多于提供参数的情况。唯一应该发生这种情况的情况是它是varargs方法,并且最后一个参数没有被提供。在这种情况下,我们将一个新空的对象数组压入栈中。

我对第二部分的具体实现不是很确定。它可能会在未来打开一些难以理解的bug。一种选择是更加谨慎,确保真的是最后一个参数,或者甚至传递{{Method}}对象(或varargs标志),以便我们“知道”我们可以期望和需要做什么。

0

评论者:ragge

我意识到我的补丁缺少两个重要的案例;Reflector的接口处理和多个匹配方法的处理。我还会查看这个问题,但还是会感激对{{MethodExpr/emitTypedArgs}}方法的反馈。

0

评论者:alexmiller

我赞成使用isVarArg()来明确处理这种情况,而不是猜测我们是否处于这种情况。我们应该检查调用varargs方法的参数过多或过少等行为(并在有必要的地方添加测试)。还要重新检查非varargs的情况是否未发生变化。

此外,请注意,作为一条一般规则,现有的AOT编译代码可能依赖于调用公共Reflector方法,因此如果您更改了公共Reflector方法的签名,您应该保留一个具有旧 arity且有某些向后兼容默认行为的版本。

0

评论者: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

评论者: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类中的 method m(String...) 和 method m(String,String...) 都匹配
MultipleVarargMethods.java:6: 错误:对m的引用不明确

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

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

)

0
参考: https://clojure.atlassian.net/browse/CLJ-440 (由ataggart报告)
...