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