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" 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',有少数几个片段不能完美应用。请参阅此处 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方法,并且方法的arity比所需arity大一,则可以匹配。这意味着它是一个我们可以调用的varargs方法,但用户还没有提供varargs参数。
  2. 在{{MethodExpr/emitTypedArgs}}中,我们处理调用方法时多出一个参数的情况。唯一应该发生这种情况的是当一个方法是一个varargs方法,最后一个参数没有被提供。在这种情况下,我们将一个新的空对象数组推送到栈上。

我对第二部分的实现并不确定。它可能会在未来打开一些难以理解的错误。一个选择是更加防御性,并确保确实是最后的参数,或者甚至传递{{Method}}对象(或varargs标志),这样我们知道预期和要求做什么。

0

由:ragge做出的评论

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

0

由:alexmiller做出的评论

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

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

0
by

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

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

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

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

)

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