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

欢迎!请参阅 关于 页面获取更多关于如何使用本站的信息。

0
编译器

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

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

将抛出异常

`
异常在 "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 报告)
...