此补丁更改了与宏一起使用时元数据的行为。现在,&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。然而,我认为这将涉及更多的工作,并且更难以测试(例如,多个arity 使事情复杂化)。似乎更合适的是将宏展开视为黑盒,然后对结果进行元数据调整,而不是修改实际的 defmacro 代码。
- 如果宏展开结果不是 IObj,例如整型,那么我的补丁会静默丢弃调用者的元数据。抛出异常是否会更好?