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