此补丁更改了在宏调用中使用元数据时的行为。元数据 &form 现在与宏调用 sexpr 的元数据合并。这使用户能够在宏调用中为内部或外部形式进行类型提示并获得较好的结果。以前,直接使用宏展开的元数据。这阻止了如下代码在没有反射的情况下工作
(.trim ^String (when true "hello "))
补丁: 2013-10-11_CLJ-865_Fix-With-Tests.diff
screened by: Timothy Baldridge
--------- 实施细节 ----------
如http://groups.google.com/group/clojure/browse_thread/thread/2690cb6ca0e8beb8中讨论的那样,当为表示宏的表达式进行类型提示时,例如使用 (.length ^String (doto (identity "x") prn)),存在一个“意外因子”。在这里,doto 宏丢弃了 &form 元数据,导致反射查找。这导致表示函数调用表达式的类型提示可以工作,但表示一般宏的表达式通常不能。可以将 doto 宏重写为尊重其 &form 元数据,但这对于每一个存在的宏来说将是乏味且容易出错的。因此,我提议对编译器进行更改,以使宏展开自动保留元数据。
附加的第一个补丁添加了对我所提议行为的测试:此测试失败。应用第二个补丁后,测试通过。
在接受我的补丁之前,有几个问题值得进一步考虑
- 我不确定我是否正确地格式化了 Java 代码。我的编辑器没有正确配置为自动获取 clojure/core 风格。
- 我的解决方案是获取 &form 元数据,删除 :line/:file 键,并将其与返回的元数据合并,其中 &form 优先。我不确定在实际情况下这是否是正确的方法,尽管它对 :tag 元数据有效。
- 我通过更改编译器实现了这一点,这是相当重的。如果不是很有必要更改编译器,则可以调整 defmacro 而不是这样做。然而,我相信这将需要大量更多的工作,且更难以测试(例如,多参数化会使问题复杂化)。似乎将宏展开视为一个黑盒,并对结果进行元数据调整会更好,而不是修改它们的实际 defmacro 代码。
- 如果宏展开的结果不是 IObj,例如 Integer,则我的补丁会静默丢弃调用者的元数据。抛出异常可能更好吗?