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

16 个答案

0

评论者:amalloy

因此我继续在 clojure.core/defmacro 而不是 clojure.lang.Compiler/macroexpand1 中进行这项更改的工作。结果比我预期的还要糟糕:我没有意识到,在引导过程中,我们还没有语法引用或应用,因此编写一个非平凡宏展开需要大量的 (list foo (list bar 'local-name)) 等等。

我相信我写的版本并不是最优的,但似乎比一开始就正确展开到正确的东西要简单,即在 piggyback 上 defn,然后使用 alter-var-root 在其中模拟元数据管理,比在正确的地方展开要简单。

无论如何,附带的补丁#3可以在 clojure.core 中而不是在 clojure.lang 中解决问题,而不是#2。补丁#1中添加的测试无论如何都通过。

0

评论者:amalloy

我意识到,我可以用一个命名私有函数代替匿名函数来做这件事,减少 defmacro 本身需要生成的混乱。我认为,如果Clojure实现优先于Java实现,补丁4将优于补丁3。

0

评论者:[email protected]

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

提议的默认宏展开行为比我们目前拥有的功能更实用,但我还想更深入地考虑以下两个细节。

1) 为了获得更有用的默认值,宏编写者无法使用其 &form 元数据,并能够控制生成的形式元数据,而无需 &form 元数据覆盖它。换句话说,宏不再完全控制其输出形式。

2) (1)上的规则有硬编码的异常::line 和:file,其中 &form 元数据无法覆盖宏返回的结果。

0

评论者:amalloy

这个补丁结合了以前针对该问题的所有补丁。

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

一个开放的疑问是:使用:explicit-meta 是否是正确的密钥?我花费了一些时间追踪到一个因为忘记关键词而错误使用了:explicit-metadata 在测试中导致的bug;可能存在更不容易混淆的东西。

0

评论作者:jafingerhut

2013年8月14日的clj-865-updated-v2-patch.txt 与Alan Malloy在2012年6月1日更新的updated.patch完全相同。我在测试文件 macros.clj 的一些上下文行因最近提交而出现问题后,简单地将补丁更新为适用于最新的master。

0

评论作者:halgari

添加了一个更新的补丁,该补丁适用于master,并从宏的元数据中移除了COLUMN_KEY。

0

评论作者:halgari

添加了一个包含所有修复内容以及几个额外测试的补丁。

0

评论作者:richhickey

因为这个可能会破坏某些东西,我们只需要在宏名称上获取元数据来请求这个

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

或者什么

0

评论者:amalloy

当然,我会准备那个补丁。不过,我担心,如果它不是默认的,那么它可能永远不会被使用,我们实际上会处于和现在相同的情况,即没有宏能正确地做到这一点。我不认为会有任何人会走遍他们的库,给每个宏添加^:keep-meta。

0

评论者:amalloy

我已经将补丁更新为像Rich要求的那样行为,但这导致了我在处理引用或私有变量方面的测试回归,我无法解决这个问题。希望其他人能够运行这些测试并找出这里缺少的内容;我的更改应该是一个可选的过程,我看不出我哪里出了问题。

0

评论作者:jafingerhut

Alan,您2013年12月3日上传的补丁clj865.patch在开头和结尾有一些不需要的HTML代码,即使去掉了这些代码,也无法干净地应用到今天最新的Clojure主分支。我理解您说还需要更多工作,但如果它能干净地应用到的话,其他人尝试时会更方便。

0

评论者:amalloy

对不起,Andy,并感谢您的提醒。我最近没有在非常友好的开发者电脑上,但我今晚会尝试修复这个补丁。

0

评论者:amalloy

这里有对这个补丁的修复。我已确认这可以干净地应用到当前的主分支。

0

评论者:amalloy

为了澄清,文件名为clj-865.patch。我没有意识到JIRA不会明确说明我随注释一起上传的文件。

0

评论作者:jafingerhut

截至Eastwood版本0.2.0,它包含一个新警告::unused-meta-on-macro,该警告会在将元数据应用于宏调用时发出,但clojure.core/fn除外,后者明确使用了应用于其自身的元数据。《[eastwood的GitHub页面](https://github.com/jonase/eastwood#unused-meta-on-macro)》

...