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 来代替对编译器的更改,但是,我认为这将需要大量工作,并更难测试(例如,多个 arities 使问题复杂化)。处理宏展开作为黑盒并随后对结果进行元数据调整似乎更好,而不是直接修改它们的 defmacro 代码。
- 如果宏展开为不是 IObj 的内容,比如整数,则我的补丁会静默地丢弃调用者的元数据。抛出异常是否更好?

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而引起的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 master上。我理解你说它还需要更多工作量,但如果有更干净的应用方式,其他人尝试起来会更容易一些。

0

评论者:amalloy

对不起Andy,感谢你注意到这个问题。我最近使用的是不太友好的开发电脑,但今晚我会尽量修复补丁。

0

评论者:amalloy

这里是对补丁的修复。我已验证这可以干净地应用到当前master上。

0

评论者:amalloy

为了明确起见,是名为clj-865.patch的文件。我没有意识到JIRA不会明确指出我上传的文件是哪一个,以及附带的评论。

0

评论者:jafingerhut

截至Eastwood版本0.2.0,它包含一个新的警告:unused-meta-on-macro,当将元数据应用于宏调用时,将发出警告,除了clojure.core/fn外,clojure.core/fn将显式地使用应用到的元数据。https://github.com/jonase/eastwood#unused-meta-on-macro

...