此补丁更改了与宏结合使用时元数据的行为。元数据 &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,那么我的补丁将静默地丢弃调用者的元数据。抛出异常是否更好?