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 发布的评论:

补丁添加对可变参数的支持。基于 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
by

评论者:alexmiller

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

0
by

评论者:ragge

我尝试了这个问题,已经附上了初步补丁,其中一部分我并不是特别确定/满意,所以欢迎提出意见。

补丁采用以下方法

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

我不太确定我对第二部分的实现。这可能导致未来出现一些难以理解的错误。一个选项是变得更防御性,并确保确实是最后一个参数,或者甚至传递 {{Method}} 对象(或变量参数标志),这样我们就 知道 期待什么以及需要做什么。

0
by

评论者:ragge

我意识到我的补丁缺少两个重要的情况:Reflecter 的接口处理和多个匹配方法的处理。我也会调查这些问题,但仍然很高兴能在 {{MethodExpr/emitTypedArgs}} 的方法中得到反馈。

0
by

评论者:alexmiller

我支持使用isVarArg()显式处理这种情况,而不是猜测我们是否处于这种状态。我们应该检查调用var args方法的参数过少、过多等情况的行为(并在需要时添加测试)。同时,也要确保非vararg情况的行为没有改变。

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

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中的方法m(String...)和MultipleVarargMethods中的方法m(String,String...)都匹配
MultipleVarargMethods.java:6: 错误:对m的引用模糊不清

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

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

)

0
...