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

欢迎!请参阅关于 页面以获取更多关于此功能的详细信息。

0 投票
编译器

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

java -Dclojure.compile.path=out -cp "./clojure-1.8.0.jar:out:src" clojure.lang.Compile implementer protocol consumer

将抛出异常

`
线程"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 投票

评论者:管理员

这里的一般排序

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

我已经长时间在思考这个问题:如果我们知道它们没有改变,是否可以避免重新加载协议。这要求我们能够知道它们没有改变。

0 投票

评论者:bronsa

也许我们可以像proxy的实现那样,为协议实现计算一个哈希值,以便检测重加载的必要性。

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