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

欢迎!请参阅关于页面以了解此工作的更多信息。

0
编译器

如果您尝试按如下方式编译所附文件(假设它们在"src"中)

java -Dclojure.compile.path=out -cp "./clojure-1.8.0.jar:out:src" clojure.lang.Compile 实现者协议 消费者

将抛出异常

`
线程"main"中的异常:java.lang.ClassCastException:implementer.Obj无法转换为protocol.Dependent,编译:(consumer.clj:5:1)

at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3657)
at clojure.lang.Compiler.compile1(Compiler.java:7474)
at clojure.lang.Compiler.compile(Compiler.java:7541)
at clojure.lang.RT.compile(RT.java:406)
at clojure.lang.RT.load(RT.java:451)
at clojure.lang.RT.load(RT.java:419)
at clojure.core$load$fn__5677.invoke(core.clj:5893)
at clojure.core$load.invokeStatic(core.clj:5892)
at clojure.core$load.doInvoke(core.clj:5876)
at clojure.lang.RestFn.invoke(RestFn.java:408)
at clojure.core$load_one.invokeStatic(core.clj:5697)
at clojure.core$compile$fn__5682.invoke(core.clj:5903)
at clojure.core$compile.invokeStatic(core.clj:5903)
at clojure.core$compile.invoke(core.clj:5895)
at clojure.lang.Var.invoke(Var.java:379)
at clojure.lang.Compile.main(Compile.java:67)

原因:java.lang.ClassCastException:implementer.Obj无法转换为protocol.Dependent

at protocol$fn__12$G__8__14.invoke(protocol.clj:3)
at protocol$fn__12$G__7__17.invoke(protocol.clj:3)
at protocol$expand_deps.invokeStatic(protocol.clj:8)
at protocol$expand_deps.invoke(protocol.clj:6)
at clojure.lang.AFn.applyToHelper(AFn.java:154)
at clojure.lang.AFn.applyTo(AFn.java:144)
at clojure.lang.Compiler$InvokeExpr.eval(Compiler.java:3652)
... 15 more

`

  • 在1.6或更早的版本中不会出现这种情况
  • 如果您不尝试调用AOT,则不会出现这种情况
  • 对于某些参数的某些排序,可能不会出现这种情况

这似乎与由两个不同的类加载器加载的类有关,并且也可能导致名称空间被编译多次。这个问题在我们生产构建中多次出现,但花了很长时间才意识到这是一个编译器问题,并且找到了一个最小示例。

3 答案

0

由admin做出评论

这里的一般顺序

  • 协议编译
  • 实现者编译
  • 作为副作用,实现者在my-obj变量中创建了一个实现协议的记录实例
  • 消费者编译,导致协议重新加载
  • 消费者在实现了旧版本协议的记录实例上调用新版本的协议

我一直在想,如果我们知道它们没有变化,是否有可能避免重新加载协议。这需要我们能够知道它们没有变化。

0

由bronsa做出评论

我们可能可以采用类似proxy实现的思路,为协议实现计算一个哈希值以检测重载的必要性。

0
参考: https://clojure.atlassian.net/browse/CLJ-2073 (由alex+import报告)
...