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

欢迎!请参阅关于页面以获取有关该功能的一些更多信息。

+1
语法与读取器

如果 data-reader 返回 nil,读取器会抛出 java.lang.RuntimeException: No dispatch macro... 该错误信息意味着,对于标签的第一个字符 happen to be 的任何值,都没有分配宏。

这是一个简单的示例

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

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

RuntimeException 没有分配宏用于:f clojure.lang.Util.runtimeException (Util.java:219)
`

原始的读取器代码没有区分数据读取器不存在的情况和从合适的数据读取器返回的 nil 值的情况。因此,它感到困惑并试图找到一个分配宏,使其进一步沿着错误代码路径向下运行,最终产生误导性的错误信息。

原始文档没有将 nil 作为一个非法值。很明显,这个 bug 是原始 data-reader 代码中的一个疏忽,而不是一个有意为之的功能。

该补丁使用一个哨兵值来区分缺少数据读取器的情况和返回 nil 的情况。

补丁: clj-1139-2.patch

15 答案

0

评论者:[email protected]

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 允许数据读取器返回 nil 而不是抛出异常。对可能的标签或记录进行了 sanity check,即JavaIdentifierStart(). 对于可能实际上是分配宏的特殊字符,给出了更好的错误信息(而不仅仅是假设它是一个带标签的字面量)。

0

评论者:[email protected]

clj-1138-data-reader-return-nil-for-no-op.patch 允许将返回 nil 的数据读取器视为无操作(类似于 #_)。对于数据读取器返回 nil 值通常没有实际作用(实际上在 Clojure 1.4 到 1.5 beta2 中会引起异常)。使用此补丁,可以像使用数据读取器一样得到类似条件功能读取器的效果。

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

按以下命令使用,补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch(日期为 2012 年 12 月 22 日)在最新的 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),补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 已不再能够干净地应用,即使是使用上面的 'git am' 命令中的 --ignore-whitespace 选项。Steve,如果您能查看需要更新的内容,那将非常好。使用在 "更新过时的补丁" 部分建议的补丁命令并不足够,因此可能需要手动仔细检查以确定需要更新什么。

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]

没有法律(Nulla poena sine lege),或者说除非你说是非法的,否则我应该能够这么做。我的一个简单例子是 {{#C NULL}},对我来说这似乎是一个明显的 nil 值。

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

我想使用数据读取器作为某种受限的读取宏(就像Common Lisp中使用的)。我就在这么做平台特定的事情时发现了这个错误(在读取条件实现之前很久)。在我的情况下,在“其他”平台上返回nil是方便的。

数据读取器的许多用法都不是双射的。例如,将{{#infix (3 + 4)}}解释为常量7,就无法做到完全往返。除非你是Dan Friedman或Wil Byrd,往返测试是一个困难的挑战。:-)

我会尝试用更多的上下文更新我的描述,但我不想让我的非传统用法分散人们对显眼错误的注意力(以及错误的信息)。
0

评论者:[email protected]

顺便说一下,这个错误是CLJ-1138,但建议的补丁说“1139”,这可能会让一些忙碌的审阅者感到困惑。

0
评论者:[email protected]

我已经测试了这个补丁,它与当前的master版本一起工作得很好。我建议添加另一个测试来确认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
...