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