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