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

欢迎!请查看关于页面了解更多关于此信息。

0
Clojure

问题

  1. 在编译器中重复了获取方法/构造函数实例的代码
  2. 解析优先重载方法的代码存在于编译器中

通过整合重复的代码,将与反射相关的部分移动到反射器,并提供一个简单的API,应该更容易阅读和理解方法解析过程。此外,对(例如,CLJ-445)关于类成员的反射机制的改进可以很大程度上与编译器分离。而且,可以清楚地识别和记录少数协调点(例如,当调用时编译器发出的参数和返回类型与反射器相同)。

15 答案

0

由:stuart.sierra 评论

自从提交 f5bcf64 以来,补丁不适用。

0

由:ataggart 评论

是的,一年前的补丁往往会这样做。

0

由:jafingerhut 评论

我不知道这有没有帮助,但亚历山大补丁的这个更新版本可以无错误地应用到截至2012年2月20日的最新Clojure头版本上。它可以编译,但无法通过ant测试。

0

评论者:bronsa

我非常愿意再次考虑这个补丁,如果有兴趣,我可以帮助将其移植到当前的主分支。

我相信任何在Compiler.java和Reflector.java之间花费时间的人都会同意这个重构/清理已经很久了。

0

评论者:michaelblume

我再次尝试将这个补丁向前移植。Java代码可以编译,并且能够编译Clojure源代码,但是然后编译clojure测试失败

`
test-example

 [java] Exception in thread "main" java.lang.IllegalArgumentException: Found multiple uncheckedByteCast methods in clojure.lang.RT for argtypes: byte, compiling:(clojure/test_clojure/numbers.clj:127:3)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6568)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6556)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$HostExpr$Parser.parse(Compiler.java:981)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6556)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5693)
 [java] 	at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:6007)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.access$200(Compiler.java:38)
 [java] 	at clojure.lang.Compiler$LetExpr$Parser.parse(Compiler.java:5957)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5693)
 [java] 	at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2182)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5693)
 [java] 	at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5124)
 [java] 	at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3753)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$InvokeExpr.parse(Compiler.java:3565)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6563)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$TryExpr$Parser.parse(Compiler.java:2153)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5691)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5691)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:5693)
 [java] 	at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5124)
 [java] 	at clojure.lang.Compiler$FnExpr.parse(Compiler.java:3753)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6559)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6549)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$MapExpr.parse(Compiler.java:2882)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6360)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler$DefExpr$Parser.parse(Compiler.java:559)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6352)
 [java] 	at clojure.lang.Compiler.analyze(Compiler.java:6313)
 [java] 	at clojure.lang.Compiler.eval(Compiler.java:6624)
 [java] 	at clojure.lang.Compiler.load(Compiler.java:7047)
 [java] 	at clojure.lang.RT.loadResourceScript(RT.java:370)
 [java] 	at clojure.lang.RT.loadResourceScript(RT.java:361)
 [java] 	at clojure.lang.RT.load(RT.java:440)
 [java] 	at clojure.lang.RT.load(RT.java:411)
 [java] 	at clojure.core$load$fn__5424.invoke(core.clj:5848)
 [java] 	at clojure.core$load.doInvoke(core.clj:5847)
 [java] 	at clojure.lang.RestFn.invoke(RestFn.java:408)
 [java] 	at clojure.core$load_one.invoke(core.clj:5653)
 [java] 	at clojure.core$load_lib$fn__5373.invoke(core.clj:5693)
 [java] 	at clojure.core$load_lib.doInvoke(core.clj:5692)
 [java] 	at clojure.lang.RestFn.applyTo(RestFn.java:142)
 [java] 	at clojure.core$apply.invoke(core.clj:628)
 [java] 	at clojure.core$load_libs.doInvoke(core.clj:5731)
 [java] 	at clojure.lang.RestFn.applyTo(RestFn.java:137)
 [java] 	at clojure.core$apply.invoke(core.clj:628)
 [java] 	at clojure.core$require.doInvoke(core.clj:5814)
 [java] 	at clojure.lang.RestFn.invoke(RestFn.java:408)
 [java] 	at user$eval72.invoke(run_test.clj:6)
 [java] 	at clojure.lang.Compiler.eval(Compiler.java:6620)
 [java] 	at clojure.lang.Compiler.load(Compiler.java:7047)
 [java] 	at clojure.lang.Compiler.loadFile(Compiler.java:7003)
 [java] 	at clojure.main$load_script.invoke(main.clj:274)
 [java] 	at clojure.main$script_opt.invoke(main.clj:336)
 [java] 	at clojure.main$main.doInvoke(main.clj:420)
 [java] 	at clojure.lang.RestFn.invoke(RestFn.java:408)
 [java] 	at clojure.lang.Var.invoke(Var.java:379)
 [java] 	at clojure.lang.AFn.applyToHelper(AFn.java:154)
 [java] 	at clojure.lang.Var.applyTo(Var.java:700)
 [java] 	at clojure.main.main(main.java:37)
 [java] Caused by: java.lang.IllegalArgumentException: Found multiple uncheckedByteCast methods in clojure.lang.RT for argtypes: byte
 [java] 	at clojure.lang.Reflector.getMatchingParams(Reflector.java:385)
 [java] 	at clojure.lang.Reflector.getMatchingMember(Reflector.java:419)
 [java] 	at clojure.lang.Reflector.getMatchingMethod(Reflector.java:485)
 [java] 	at clojure.lang.Reflector.getMatchingStaticMethod(Reflector.java:499)
 [java] 	at clojure.lang.Compiler$StaticMethodExpr.<init>(Compiler.java:1578)
 [java] 	at clojure.lang.Compiler$HostExpr$Parser.parse(Compiler.java:983)
 [java] 	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6561)
 [java] 	... 110 more

`

0

评论者:michaelblume

clj-793-v4有一个有用的属性,即在每个提交时编译,这使得二分查找更容易,尽管测试仍然没有运行

测试似乎在“将getMatchingParams方法从Compiler移动到Reflector”时开始失败,这个看起来对我而言完全是无害的改变,因此我有些困惑。

0

评论者:michaelblume

Aha,试着只用IntelliJ重构和比较来移动getMatchingParams,看起来是“tied = false”的分配被丢失了。这修复了测试错误,但留下了一个新的错误。正在二分查找...

0

评论者:michaelblume

顺便说一下,我非常感谢亚历山大·塔加特编写这个补丁,作为一个系列的小提交,这样就可以相对容易地移植/二分查找。

0

评论者:michaelblume

好,这个有了tied=false的修复,但有个新问题

在“将实例方法查找代码从编译器移动到反射器”中,要从编译器移动的代码中有两个不同的RT.errPrintWriter调用,它们使用了只有在编译器中才有的大量信息(列、行等)。当这段代码被移动到反射器后,我在前向迁移中尝试了巧妙的方法,仅仅在编译器中的一个位置留下错误打印,但这不起作用,因为两次调用打印了不同的消息。我并不确定如何将这段代码转移到反射器中。

相关变动也在https://github.com/MichaelBlume/clojure/commit/56995f3376795a3cfcfc6339e7d8ad24d8459d31

查找对RT.errPrintWriter的调用,你就能看到发生了什么变化。

0
作者

评论者:michaelblume

总结来说,可能有更好的表述,这个补丁将一些代码从编译器移动到它的独立方法中,在补丁最初编写时相对容易,但现在有些额外的反射警告打印需要知道行/列信息,这些信息在编译器的原始位置中可用,但在反射器中提取的功能中不可用。我们可以将行/列传递到该方法中,但那样我们就必须最终将这些值通过几个其他反射器方法,这听起来很糟糕。或者,我们可以从这个反射器方法中传递一个指示,说明它如何未成功找到方法,以便编译器方法可以自己做出打印失败的决定,这可能涉及发明异常或某种 Success/Failure ADT。

0
作者

评论者:bronsa

迈克尔,你考虑过这样做吗?

if (Reflector.getMethods(target.getJavaClass(), args.count(), methodName, false) == null) RT.errPrintWriter().format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (no such method).\n", SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName()); else RT.errPrintWriter().format("Reflection warning, %s:%d:%d - call to method %s on %s can't be resolved (argument types: %s).\n",SOURCE_PATH.deref(), line, column, methodName, target.getJavaClass().getName(), getTypeStringForArgs(args));

在以
`
if(method == null && RT.booleanCast(RT.WARN_ON_REFLECTION.deref()))`

开头的块中? Compiler.java?

0
作者

评论者:michaelblume

这听起来是合理的,但后来在Reflector.getMethods被替换为私有getMethodsForName时,会遇到麻烦,但我们可以尝试解决这个问题...

0
作者

评论者:michaelblume

不,仍然没有打印出正确的警告

`

 [java] Testing clojure.test-clojure.rt
 [java]
 [java] FAIL in (error-messages) (rt.clj:43)
 [java] reflection cannot resolve instance method because it is missing
 [java] expected: (clojure.core/re-matches #"Reflection warning, .*:\d+:\d+ - call to method zap on java\.lang\.String can't be resolved \(no such method\)\.\r?\n" (clojure.test-helper/with-err-string-writer (clojure.test-helper/eval-in-temp-ns (defn foo [x] (.zap x 1)))))
 [java]   actual: (not (clojure.core/re-matches #"Reflection warning, .*:\d+:\d+ - call to method zap on java\.lang\.String can't be resolved \(no such method\)\.\r?\n" "Reflection warning, /Users/michael.blume/workspace/clojure/src/script/run_test.clj:45:28 - call to method zap on java.lang.String can't be resolved (argument types: long).\n"))
 [java]
 [java] FAIL in (error-messages) (rt.clj:43)
 [java] reflection cannot resolve instance method because it is missing
 [java] expected: (clojure.core/re-matches #"Reflection warning, .*:\d+:\d+ - call to method zap on java\.lang\.String can't be resolved \(no such method\)\.\r?\n" (clojure.test-helper/with-err-print-writer (clojure.test-helper/eval-in-temp-ns (defn foo [x] (.zap x 1)))))
 [java]   actual: (not (clojure.core/re-matches #"Reflection warning, .*:\d+:\d+ - call to method zap on java\.lang\.String can't be resolved \(no such method\)\.\r?\n" "Reflection warning, /Users/michael.blume/workspace/clojure/src/script/run_test.clj:45:28 - call to method zap on java.lang.String can't be resolved (argument types: long).\n"))

`

0

评论者:michaelblume

v5 版本的补丁系列也在这里:https://github.com/MichaelBlume/clojure/commits/compile-refactor
带有 Nicolo 建议的补丁系列在:https://github.com/MichaelBlume/clojure/commits/compile-refactor-nicolo

0
参考:[https://clojure.atlassian.net/browse/CLJ-792](https://clojure.atlassian.net/browse/CLJ-792)(ataggart 报告)
...