请分享您的想法,参加 2024 年 Clojure 状态调查!

欢迎!请查看 关于 页面以了解更多关于其工作原理的信息。

+1 投票
语法和读取器

如果 data-reader 返回 nil,读取器将抛出 java.lang.RuntimeException: 无分发宏... 错误信息暗示没有针对标签的第一个字符所对应分发宏。

这里有一个简单的例子

`
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 识别为非法值。很明显,这个错误是原始数据读取器代码中的一个疏忽,而不是一个故意特性。

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

补丁: clj-1139-2.patch

15 答案

0 投票

评论由:[email protected] 提供

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

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 值并将其作为最终值返回。我认为它实现了最初为分派宏设计的功能,并在很多情况下提供了更好的错误消息(大多数是打字错误)。

第二个补丁 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 仍可干净地应用于最新主版本

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

没有使用 --ignore-whitespace 选项,补丁失败仅在最近 Clojure 主版本中某些空白字符发生变化。

0 投票

评论者:jafingerhut

好的,现在使用最新主版本(1.5.0-RC15,为此刻),补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 无法干净地应用,即使在上述 'git am' 命令中使用 --ignore-whitespace。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。有没有好用的用例需要这样?看起来你正在阅读reader中非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,可逆性是一个艰巨的要求。:-)

我会尝试提供更多上下文来更新我的描述,但我不想让我的非传统用法分散人们对显然的bug(和错误信息)的注意力。
0 投票
by

评论由:[email protected] 提供

顺便说一下,这个bug是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
...