请在2024 Clojure现状调查中分享您的想法!

欢迎!请访问关于页面,以了解更多有关此工作方式的信息。

0投票
Clojure

在尝试定义一个名为“clear”的方法的协议时似乎存在问题

(defprotocol PClear

 (clear (link: o)))

=> PClear

(defrecord Foo (link: )

 PClear 
   (clear (link: o) o))

=> CompilerException java.lang.ClassFormatError: Duplicate method name&signature in class file xxxx/Foo, compiling:(NO_SOURCE_PATH:1:1)

我认为这是由于与底层实现中Java方法Collection.clear()的名称冲突。然而,这个错误对此点不太清晰,并且我认为潜在的风险尚未在文档中描述。

似乎有两种方法可以解决这个问题
a) 禁止使用"clear"作为协议方法名称(在这种情况下,错误应该提供更多信息,规则应予以记录)
b) 在类文件格式中找到支持此功能的方法(可能通过在JVM返回类型上重载,因为Collection.clear()返回void??)

6 答案

0投票

评论者:bronsa

Mike,JVM不支持重载返回类型,因此您的第二个建议在技术上不可行。

阅读defrecord {quote} 该类将自动生成几个接口的实现:IObj (元数据支持) 和
IPersistentMap,以及它们的所有超接口。
{quote}
{quote}

也许应该在这里提到java.util.Collection(或者更好,java.util.Map)。

0投票

评论者:alexmiller

我认为这是一个文档增强请求。

0投票

评论者:sohta

这可能超出了此问题的范围,但协议方法冲突可能会引起其他类型的错误

`
user=> (defprotocol P1 (finalize [this]))
P1
user=> (defrecord R1 [] P1 (finalize [this]))

编译时错误:java.lang.VerifyError: (类:user/R1,方法:finalize 签名:()Ljava/lang/Object;) 无法从空栈中弹出操作数,编译:...
user=> (defprotocol P2 (wait [this]))
P2
user=> (defrecord R2 [] P2 (wait [this]))
user.R2
user=> (def r (->R2))

'user/r

user=> (wait r)
编译时错误:java.lang.IllegalArgumentException: 在接口:user.P2 中找不到单个方法:wait,用于协议方法:P2的函数:wait,编译:...
user=>
`

在我看来,如果 defprotocol 能够警告方法冲突,并用更具体的信息,将会更好。

0投票

评论者:mikera

@Nicola Mometto:我认为 JVM 确实支持重载返回类型

“请注意,一个类中可能有多个匹配的方法,因为尽管 Java 语言禁止类声明具有相同签名但返回类型不同的多个方法,但 Java 虚拟机并不禁止。虚拟机的这种灵活性可以用来实现各种语言功能。例如,可以通过桥接方法实现协变返回;桥接方法和被覆盖的方法将具有相同的签名但不同的返回类型。”

查看: http://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getMethod-java.lang.String-java.lang.Class...-

0投票

评论者:bronsa

啊,当然,谢谢。

0投票
参考: https://clojure.atlassian.net/browse/CLJ-1791(由 mikera 报告)
...