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

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

0
Clojure

问题

  1. 在编译器中重复代码以获取方法/构造函数实例
  2. 解决重载方法的首选方法代码位于编译器中

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

15 个答案

0

由:stuart.sierra发表的评论

补丁无法在提交f5bcf64时应用。

0

由:ataggart发表的评论

是的,一年前的补丁往往如此。

0

由:jafingerhut发表的评论

我不知道这有没有帮助,但截至2012年2月20日的最新版本的Alexander的补丁能干净地应用到Clojure的最新-version上。它可以编译,但是没有通过ant测试。

0

评论者:bronsa

我很想再次考虑这个补丁,如果有兴趣的话,我可以帮助将补丁移植到当前的master版本中。

我相信任何花费时间在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

啊哈,试图仅使用IntelliJ重构移动getMatchingParams并比较,结果“tied = false”的赋值似乎被丢弃了。这修复了那个测试错误,但留下了新的一个。正在二分搜索...

0

评论者:michaelblume

顺便说一句,我很感激Alexander Taggart因为这个补丁作为一个系列的微量提交,这使得它相对容易移植/二分搜索。

0

评论者:michaelblume

ok,这个修复了 tied=false 的问题,但出现了新的问题

在“将实例方法查找代码从 Compiler 移至 Reflector”中,即将移出 Compiler 的代码对 RT.errPrintWriter 进行了两次调用,使用了只有 Compiler 中才有的大量信息(列编号、行编号等)。当这段代码移至 Reflector 时,我在 forward-port 中试图变得聪明一些,只想在 Compiler 中保留错误打印的单一位置,但这不起作用,因为两个调用打印了不同的消息。我实际上不确定如何将这部分代码移动到 Reflector 中。

相关的更改也位于 https://github.com/MichaelBlume/clojure/commit/56995f3376795a3cfcfc6339e7d8ad24d8459d31

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

0

评论者:michaelblume

为了更好地总结,这个补丁将一些代码从 Compiler 移至 Reflector 的独立方法中,这部分代码在补丁最初编写时相对容易移动,但现在有一些额外的反射警告打印,需要知道位于 Compiler 中原始位置的行/列信息,但提取函数在 Reflector 中没有这些信息。我们可以将行/列传递到该方法中,但那样的话,我们就必须最终将它们传递给其他几个 Reflector 方法,听起来很不好。或者,我们可以传递一个指示给那个反射方法,关于它如何未能找到方法,以便 Compiler 方法可以根据自己如何打印失败做出决定,但这可能涉及发明异常或某种 Success/Failure ADT。

0

评论者:bronsa

Michael,你考虑过这样做吗?

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()))`

开始的代码块中?

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 (由ataggart报告)
...