2024 Clojure 状态调查! 中分享您的想法。

欢迎!请查看 关于 页面,以获取更多关于如何使用本站的详细信息。

0 投票
编译器

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

16 答案

0 投票

评论由:amalloy

所以我选择了在clojure.core/defmacro而不是clojure.lang.Compiler/macroexpand1中进行这个更改的工作。结果比我预期的还要糟糕:我没有意识到在引导阶段我们还没有syntax-quote或apply,因此非平凡的宏展开需要大量的(list foo (list bar 'local-name))等等。

我确信我写的版本不是最优的,但是与正确展开到正确的东西相比,似乎通过依赖defn并在其中使用alter-var-root来模拟元数据管理要简单一些。

无论如何,可以应用补丁#3来替换#2,以解决clojure.core中的问题,而不是clojure.lang。补丁#1中添加的测试无论如何都能通过。

0 投票

评论由:amalloy

我意识到可以用命名私有函数而不是匿名函数来做这件事,这样可以减少defmacro本身需要生成的混乱。我认为,如果Clojure实现比Java实现更受欢迎,那么补丁4比补丁3要好得多。

0 投票

评论由:[email protected]

我更喜欢补丁0002在Java上而不是0003或0004。补丁0002将如何调用宏函数(特别是额外的&form和&env参数)的知识保留在一个地方,即macroexpand1,而不是在core.clj中重复该知识。注意补丁0001只是测试。

建议的默认宏展开行为比我们目前拥有的更有用,但有两大细节我想再考虑一下。

1) 为了获得更有用的默认值,宏编写者失去了消费他们的&form元数据和在没有&form元数据覆盖的情况下控制结果形式元数据的能力。也就是说,宏不再是它们输出形式的完全控制者。

2) 上面的规则(1)为:line和 :file提供了硬编码的例外,在这些例子中,&form元数据无法覆盖宏返回的结果。

0 投票

评论由:amalloy

该补丁综合了此问题的所有之前补丁。

在clj-dev邮件列表中,Andy Fingerhut 提出了一个新元数据键,允许宏作者指定“我已经查看他们的形式元数据,这正是我想展开的形式,请不要再更改元数据。” 我已经实现了这个功能,并认为它解决了 Chouser 关于需要一种“跳出”改进默认行为的方法的担忧。

一个未解决的问题::explicit-meta 是否是正确的键?我花了一些时间追踪一个由忘记关键字和使用 :explicit-metadata 在测试中引起的错误;可能有一些更难混淆的东西可用。

0 投票

评论者:jafingerhut

2013年8月14日的clj-865-updated-v2-patch.txt与Alan Malloy的2012年6月1日更新的updated.patch相同。我仅仅是更新了这个补丁,以便在测试文件macros.clj中的一些上下文行由于最近的提交而出错后,干净地应用到最新的主分支上。

0 投票

评论者:halgari

添加了适用于主分支的更新补丁,并也从宏的元数据中移除了 COLUMN_KEY

0 投票

评论者:halgari

添加了包含所有修复和一些额外测试的补丁。

0 投票

评论者:richhickey

鉴于这可能会破坏东西,我们只需在宏名称上拿元数据来要求这样

(defmacro ^:keep-meta simple-macro [f arg] `(~f ~arg))

或者某种方式

0 投票

评论由:amalloy

当然,我会准备那个补丁。但我担心,如果它不是默认的,那么它将永远不会被使用,我们实际上会处于现在的同一情况,即没有宏这样执行。我不认为任何人会走遍他们的库,在每个宏上添加 ^:keep-meta。

0 投票
作者:

评论由:amalloy

我已经根据Rich的要求更新了补丁,但它导致了一个无法解决的测试回归问题,无论是处理引用变量还是私有变量。希望其他人可以运行测试并找出这里缺少了什么;我的更改应该是可选的,我看不出我错在哪里。

0 投票
作者:

评论者:jafingerhut

艾伦,你于2013年12月3日提交的补丁clj865.patch在开头和结尾有一些HTML冗余,即使移除这些冗余,今天应用到最新的Clojure master版本上也不会干净地应用。我理解你说这还需要更多的工作,但如果它能够干净地应用,对那些希望尝试的人来说会更容易。

0 投票
作者:

评论由:amalloy

抱歉,安迪,谢谢您的提醒。我最近没有使用过非常友好的开发电脑,但今晚我会设法修复这个补丁。

0 投票
作者:

评论由:amalloy

这是补丁的修复方法。我验证了它在当前master版本上可以干净地应用。

0 投票
作者:

评论由:amalloy

为了澄清,文件名为clj-865.patch。我没有意识到Jira不会明确指出我随评论上传的文件。

0 投票
作者:

评论者:jafingerhut

截至Eastwood版本0.2.0,包括一个新的警告:unused-meta-on-macro,当将对宏调用应用元数据时(已知clojure.core/fn除外,它明确使用了它应用到的元数据)会发出警告。 https://github.com/jonase/eastwood#unused-meta-on-macro

...