此补丁修改了宏与元数据一起使用时的行为。现在,元数据 &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 元数据,但对现有所有宏进行此操作既乏味又容易出错。相反,我提议修改编译器,使宏展开自动保留元数据。
附加的第一个补丁为我的提议添加了一个测试:该测试失败。应用第二个补丁后,测试通过。
在我接受我的补丁之前,有几个问题需要进一步考虑
- 我不确定我实际上 whether Java 代码格式正确。我的编辑器并没有很好地自动配置 clojure/core 风格。
- 我的解决方案是获取 &form 元数据,删除 :line/:file 键,然后与返回的元数据合并,其中 &form 优先。我不确定这是否是所有情况下都正确的方法,尽管它对于 :tag 元数据有效。
- 通过修改编译器实现了这一目标,这使得它相当重。相反,可以调整 defmacro,但如果不希望修改编译器,这可能需要更多的工作并且更难以测试(例如,多参数会使事情复杂化)。看起来,将宏展开视为一个黑盒子,然后对结果进行元数据调整,而不是修改实际的 defmacro 代码,似乎是更好的方法。
- 如果宏展开成某种不是 IObj 的东西,比如一个 Integer,那么我的补丁默默地丢弃了调用者的元数据。抛出异常会更好吗?