此补丁更改了宏与宏调用 sexpr 合并用时元数据的行为。现在,元数据 &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,则我的补丁会静默丢弃调用者的元数据。抛出异常会更好吗?