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

欢迎!请参阅关于页面了解更多有关此工作方式的信息。

+1
语法和读取器

如果数据读取器返回nil,则读取器会抛出java.lang.RuntimeException: No dispatch macro... 错误消息暗示对于标签的第一字符所对应的分派宏不存在。

以下是一个简单的例子

`
user=> (binding [*data-readers* {'f/ignore (constantly nil)}]

     (read-string "#f/ignore 42 10"))

RuntimeException No dispatch macro for: f clojure.lang.Util.runtimeException (Util.java:219)
`

原始的读取器代码没有区分数据读取器的缺失和一个数据读取器的适当返回值nil。因此,它感到困惑,并试图找到分派宏,导致它沿着错误的代码路径进一步下探,最终给出一个误导性的错误消息。

原始文档中没有将nil视为非法值。显然,这个bug是原始数据读取器代码中的一个疏忽,而不是一个有意为之的功能。

这个补丁使用哨兵值将缺失的数据读取器情况与nil返回值情况区分开来。

补丁: clj-1139-2.patch

15 个回答

0

由:[email protected]发表的评论

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 允许数据读取器返回nil而不是抛出异常。它会进行逻辑检查以确认可能的标签或记录是否为JavaIdentifierStart(). 对于可能实际上是分派宏的特殊字符给出了更好的错误消息(而不是假定它是一个标标签字面量)。

0

由:[email protected]发表的评论

clj-1138-data-reader-return-nil-for-no-op.patch 允许数据读取器返回 nil,由读取器将其视为空操作(类似于 #_)。对于数据读取器返回 nil 通常不是一个有用的值(实际上它在 Clojure 1.4 到 1.5 测试版 2 中会引发异常)。有了这个补丁,可以使用数据读取器实现类似条件功能读取器的功能。

0

由:[email protected]发表的评论

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 是首先考虑的补丁。它只是允许数据读取器返回 nil 值,并将最终值返回为 nil。我认为它实现了最初针对分派宏的目的,并在许多情况下提供了更好的错误消息(大多数是拼写错误)。

第二个补丁 clj-1138-data-reader-return-nil-for-no-op.patch 依赖于第一个补丁的实施。它额外的一步是将数据读取器返回的 nil 值视为读取器的无操作(类似于 #_)。

0

由:[email protected]发表的评论

事实上,你可以通过让你的数据读取器返回 '(quote nil)' 而不是纯粹的 nil 来绕过原始问题。这个表达式方便地评估为 nil,因此你可以在必要时获取一个 nil。在应用补丁之后,这也适用,所以如果你真的想返回 nil,仍然还有这种方法。

(binding (link: *data-readers* {'x/nil (constantly '(quote nil))}) (read-string "#x/nil 42"))
;=> (quote nil)
0

评论者:jafingerhut

如果使用以下命令,则日期为 2012 年 12 月 22 日的 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 补丁仍然适用于最新的 master 版本

% git am --keep-cr -s --ignore-whitespace < clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch

如果不使用 --ignore-whitespace 选项,则补丁会因为 Clojure master 最近更改的一些空白而失败。

0

评论者:jafingerhut

好的,现在使用最新的 master(当时为 1.5.0-RC15),如果使用上面给出的 'git am' 命令中的 '--ignore-whitespace',则补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 不再干净地应用。Steve,如果您能查看需要更新哪些内容,那将非常棒。使用 "更新旧的补丁" 部分http://dev.clojure.org/display/design/JIRA workflow 中建议的补丁命令不够,因此可能需要手动仔细检查,以确定哪些需要更新。

0

由:[email protected]发表的评论

我已提交我的补丁。最近LispReader和新的EdnReader有一些变化。

0

评论者:alexmiller

修复了空白符警告并更新了补丁,使其生效,未更改语义,在 clj-1139-2.patch 中保留了归属。

0

评论者:alexmiller

任务需要更好地描述问题和采用的方法。

0

由:[email protected]发表的评论

如果问题不明确,我会问为什么应特别处理返回nil的数据读取器?如果它按设计认为是非法的,这个错误信息让用户理解了吗?

在提交错误时,我没有找到任何文档化的限制,现在我仍然找不到。所以这似乎是一个简单的错误。数据读取器应该允许返回nil,Clojure读取器应该像往常一样处理nil。我的解决方案是返回(quote nil),这给出了预期的行为,而没有触发错误。

0

评论者:alexmiller

感谢更详细的描述。我的问题是,调用数据读取器函数后,是否应该返回nil?是否有什么合理的用例需要这种方式?这看起来您在使用读取器读取一个非nil的标签值,因此返回nil是令人困惑的。这不可能进行双向转换,因此看起来是不对称的。

0
评论者:[email protected]

没有法律,就没有惩罚,或者说,除非你说它是非法的,否则我可以这样做。我的简单例子是{{#C NULL}},这在我看来显然是nil。

回顾这个问题,我发现大多数人认为标记字面量是Clojure中编码外值的方式。如果你只关心可扩展的数据表示,谁还需要另一种表示nil的方法呢?这是一个合理的问题。

我曾想将数据读取器用作某种受限的读取宏(类似于Common Lisp中使用的)。在我进行特定平台操作时发现了这个bug(在读取条件实现之前很久)。在这种情况下,对其他平台返回nil很方便。

数据读取器的许多用法不是双射的。例如,将{{#infix (3 + 4)}} 解释为常量7,同样也无法双向转换。除非你是Dan Friedman或Wil Byrd,双向转换是一个困难的要求。:-)

我将尝试用更多上下文更新我的描述,但我不想让任何人因我非传统的使用而分散了对明显错误的注意(和错误消息)。
0

由:[email protected]发表的评论

顺便说一下,这个bug是CLJ-1138,但提出的补丁说"1139",可能会让一些忙碌的审阅者感到困惑。

0
评论者:[email protected]

我测试了补丁,它在我的当前主分支上工作得很好。我建议添加另一个测试来确认edn/read-string也能正确工作。这里是我的测试代码。这也测试了覆盖默认读取器是否有效。如果你需要,请随时使用这个测试。


(deftest clj-1138-uuid-override
  (is (nil? (binding [*data-readers* {'uuid (constantly nil)}]
              (read-string "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))))
  (is (nil? (edn/read-string {:readers {'uuid (constantly nil)}}
                                 "#uuid \"550e8400-e29b-41d4-a716-446655440000\""))))

0
...