此补丁更改了与宏一起使用时元数据的行为。现在,&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 的东西,例如整数,那么我的补丁会静默地丢弃调用者的元数据。抛出一个异常会更好吗?