此补丁改变了与宏一起使用时的元数据行为。现在,元数据 &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,但这需要大量的工作并且更难测试(例如,多个 arity 会使事情变得复杂)。似乎更好将宏扩展视为一个黑盒,然后对结果进行元数据调整,而不是修改它们的实际 defmacro 代码。
- 如果宏扩展成不是一个 IObj,例如一个 Integer,则我的补丁会静默地丢弃调用者的元数据。是否抛出异常会更好?