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 区分为一个非法值。很明显,这个错误是原始数据读取器代码中的疏忽,而不是一个故意添加的功能。

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

补丁: clj-1139-2.patch

15 个答案

0 投票

评论者:[email protected]

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 允许数据读取器返回 nil 而不是抛出异常。它对可能的标签或记录执行简单的检查,并给出更好的错误信息,对于可能是分配宏的特殊字符(而不是假设它是带标签的字面量)。

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 的 "Updating stale patches" 部分中建议的补丁命令不足以解决问题,因此可能需要手动仔细检查需要更新的内容。

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 投票
参考:[https://clojure.atlassian.net/browse/CLJ-1138](https://clojure.atlassian.net/browse/CLJ-1138)(由[email protected]报告)
...