此补丁修改了与宏结合使用时的元数据行为。现在,元数据 &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 来代替对编译器的更改,但是,我认为这将需要大量工作,并更难测试(例如,多个 arities 使问题复杂化)。处理宏展开作为黑盒并随后对结果进行元数据调整似乎更好,而不是直接修改它们的 defmacro 代码。
- 如果宏展开为不是 IObj 的内容,比如整数,则我的补丁会静默地丢弃调用者的元数据。抛出异常是否更好?