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

补丁添加了对可变参数 的支持。构建在 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',只有几个片段不适用。请参阅这里的“更新过时的补丁”部分: http://dev.clojure.org/display/design/JIRA+workflow

0

评论者:jafingerhut

唉。删除了附件,因为它是为 CLJ-445 的,或者至少它被命名为这样。CLJ-445 一定有一个漫长的评论历史,因此如果您或多个补丁解决了此问题,则可以阅读那里的讨论以了解历史。

我不了解任何“挂起”状态的票据,除了Rich Hickey在一两条评论中明确表示要在改变之前等待一段时间的情况外。只是一些贡献者选择工作的票据和一些审核者选择审核的票据。

0

评论作者:alexmiller

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

0

评论作者:ragge

我对此有过尝试,已附上初步补丁,其中一些部分我不太确定/满意,因此欢迎反馈。

该补丁采取以下方法

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

我不太确定关于第二个部分的实现。这可能会在将来造成一些难以理解的错误。一个选项可能是更具防御性,并确保它确实是最后一个参数,例如,或传递 {{Method}} 对象(或 varargs 标志),以便我们 知道 我们可以期待什么,需要做什么。

0

评论作者:ragge

我意识到我的补丁缺少两个重要的情况;Reflector 中的接口处理和在多个匹配方法中的处理。我也将检查这一点,但仍然欢迎对在 {{MethodExpr/emitTypedArgs}} 中的方法的反馈。

0

评论作者:alexmiller

我赞同使用 isVarArg() 来显式处理此情况,而不是猜测我们是否处于这种情况。我们应该检查调用参数不足、过多的 varargs 方法的行为(并在需要的地方添加测试),并且也要再次检查非 varargs 情况未改变行为。

此外,请注意,作为一般规则,现有的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报告)
...