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