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

欢迎!请参阅关于页面,了解有关此功能的更多信息。

+1
语法和reader

如果数据reader返回nil,则reader会抛出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)
`

原始的reader代码没有区分没有数据reader和适当的data-reader返回nil的情况。它因此感到困惑,试图找到一个寄存器宏,导致其沿着错误代码路径进一步执行,最终产生误导性的错误消息。

原始文档中没有将nil视为非法值。显然,这个bug是原始data-reader代码中的疏忽,而不是有意的设计。

补丁使用哨兵值将缺失的数据reader案例与返回nil值案例区分开。

补丁: clj-1139-2.patch

15 个答案

0

评论由:[email protected]发表

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch允许数据reader返回nil而不是抛出异常。进行可能的标签或记录是JavaIdentifierStart()的健壮性检查。为可能实际上是寄存器宏的特殊字符提供更好的错误消息(而不是假设它是一个标记字面量)。

0

评论由:[email protected]发表

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

0
by

评论由:[email protected]发表

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 是考虑的第一个补丁。它仅允许数据读取器返回 nil 作为最终值。我认为它实现了最初的分派宏意图,并在许多情况下提供了更好的错误信息(大多数是错误)。

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

0
by

评论由:[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
by

评论者:jafingerhut

如果使用以下命令,补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 仍然可以干净地应用到最新的版本(截至 2012年12月22日):

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

如果不使用 --ignore-whitespace 选项,补丁会失败,因为 Clojure master 最近更改了某些空白字符。

0
by

评论者:jafingerhut

好的,现在使用最新的 master(当时为 1.5.0-RC15),补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 也不能干净地应用,即使在 'git am' 命令中使用了 --ignore-whitespace 选项。Steve,如果你能查看需要更新的内容,那将非常好。使用 "更新过时的补丁" 部分中建议的 patch 命令还不够,因此可能需要手工仔细检查以确定需要更新的内容。

0

评论由:[email protected]发表

我已移除我的补丁。最近LispReader和新的EdnReader有了一些变化。

0

评论者:alexmiller

解决了空白符警告,更新了补丁,使其能够应用,没有语义上的更改,归功于clj-1139-2.patch。

0

评论者:alexmiller

票证需要更有细节的描述问题以及补丁中采取的方法。

0

评论由:[email protected]发表

如果问题不明确,我会问为什么会导致数据读取器返回nil会被特别对待?如果是出于设计考虑将其视为非法,那么这个错误信息是否能够启发用户呢?

在提交此错误之前以及今天,我都没有找到任何关于此的限制性文档。因此,这看起来像是一个简单的错误。数据读取器应该允许返回null,而Clojure读取器应该像往常一样处理null。我的权宜之计是返回(quote nil),这样就能得到预期的行为而不会触发错误。

0

评论者:alexmiller

我希望对描述进行更多更新。我的问题是调用数据读取器函数时是否应该返回nil。有没有需要这种行为的好用例?这似乎你在使用读取器读取非nil标记值的描述,因此返回nil会令人困惑。这不可能是双向可转化的,因此似乎是不对称的。

0
_评论者:[email protected]_

“无法律即无罚”或基本上,除非你说它是非法的,我应该能做。我的简单例子是{{#C NULL}},这对我来说显然是空值。

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

我想使用数据读取器作为类似封装的读取宏(如Common Lisp中使用的)。我在进行特定平台的工作时发现了这个错误(在读取条件实现之前很久)。在我的情况下,在“其他”平台上返回nil很方便。

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

我将尝试用更多上下文更新我的描述,但我不想让我的非常规用法分散人们对显然的漏洞(和糟糕的错误信息)的注意力。
0
by

评论由:[email protected]发表

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

0
by
_评论者:[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
by
...