此补丁更改了在使用宏时元数据的行为。现在元数据 &form 与宏调用 sexpr 的元数据合并。这使得用户可以在宏调用中为内部或外部形式进行类型提示,并获得更好的结果。过去,宏展开的元数据是直接使用的。这不允许如下代码无反射地工作:
(.trim ^String (when true "hello "))
补丁: 2013-10-11_CLJ-865_Fix-With-Tests.diff
审核: 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,那么我的补丁会静默丢弃调用者的元数据。抛出异常会更好吗?