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

欢迎!请查看 关于 页面以获取更多关于这个工如何工作的一些信息。

0
Clojure

问题

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

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

15 个答案

0

由 stuart.sierra 发布的评论:

在提交 f5bcf64 时,补丁不适用。

0

由 ataggart 发布的评论:

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

0

由 jafingerhut 发布的评论:

我不知道这是否有帮助,但是这个 Alexander 补丁的更新版本于 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 发布

啊哈,试着重用 IntelliJ 重构并用对比,看起来是某个地方掉了 assign "tied = false",这修复了测试错误,但留下了新错误。正在二分查找...

0

评论由:michaelblume 发布

顺便说一句,我非常感谢 Alexander Taggart 编写这个补丁,以一系列小提交的形式,这样就可以相对容易地转发/二分。

0

评论由:michaelblume 发布

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

在“将实例方法查找代码从编译器移动到反射器”中,被移动出编译器的代码中存在两个不同的调用RT.errPrintWriter,这使用了只有在编译器中才有的大量信息(列、行等)。当这段代码被移动到反射器时,我在前向端口中试图做一些巧妙的设计,只在一处保留错误打印,但这不起作用,因为这两个调用打印了不同的信息。我实际上不确定如何将这个功能移动到反射器。

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

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

0

评论由:michaelblume 发布

为了更好地概括,可能有以下代码是从编译器移动到反射器中独立的方法的,当这个补丁最初编写时,移动相对容易,但现在有一些额外的反射警告打印,希望知道行/列等东西,这些在编译器原始位置中可用,但在反射器提取的函数中不可用。我们可以向那个方法传递行/列,但这将使我们必须最终通过几个其他反射器方法传递它们,这听起来很糟糕。或者,我们可以向那个反射器方法传递一个指示,说明它如何无法找到方法,这样编译器方法就可以自己决定如何打印失败,这可能涉及到发明异常或某种成功的/失败的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被替换为private getMethodsForName时,它可能遇到麻烦,但我们可以尝试解决这个问题...

0
by

评论由: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
by

评论由:michaelblume 发布

在 v5 版本中的补丁系列可在 https://github.com/MichaelBlume/clojure/commits/compile-refactor 上找到
带有 Nicolo 建议的补丁系列可在 https://github.com/MichaelBlume/clojure/commits/compile-refactor-nicolo 上找到

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