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