2024 年 Clojure 调查问卷! 中分享您的想法。

欢迎!请查看 关于 页面以了解更多关于这个工作流程的信息。

+1 投票
语法和读取器

如果数据读取器返回 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 而不是抛出异常。对可能的标签或记录执行 sanify 检查。对于可能是分派宏的特殊字符提供更好的错误消息(而不是假设它是一个标记字面量)。

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 作为最终值返回。我认为它实现了最初为分派宏设计的 intended goal,并且在很多情况下(通常是输入错误)给出了更好的错误信息。

第二个补丁,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日,如果你使用以下命令仍然可以干净地应用到最新主分支

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

如果没有 --ignore-whitespace 选项,由于 Clojure 主分支最近对空白字符进行了更改,该补丁会失败。

0 投票

评论者:jafingerhut

OK,现在使用最新主分支(当时为 1.5.0-RC15),补丁 clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch 已无法干净地应用,即使使用上面的 'git apply' 命令中的 '--ignore-whitespace' 选项也无法做到。Steve,如果您能查看需要更新的内容,那么将非常 nice。使用“过时补丁的更新”部分中建议的补丁命令还不够,可能需要仔细手工检查以查看需要更新什么。

0 投票

评论者:[email protected]

我已经移除了我的补丁。近期 LispReader 和新的 EdnReader 发生了一些变化。

0 投票

评论者:alexmiller

修复了空白符警告,并更新了补丁以便应用,没有语义上的变化, attribution 保留在 clj-1139-2.patch 中。

0 投票

评论者:alexmiller

这个工单需要更好的问题描述和补丁中采取的方法。

0 投票

评论者:[email protected]

如果问题不明确,我会问为什么一个数据读取器会特别处理 nil 返回值?如果是出于设计考虑被视为非法,这个错误消息能否让用户得到启发?

在提交bug的时候我没有找到任何文档化的限制,今天也没有找到。所以对我来说,这似乎是一个简单的错误。数据读取器应该允许返回 nil,Clojure 读取器应该像往常一样处理 nil。我的解决方案是返回 (quote nil),这使得得到了预期的行为且没有触发错误。

0 投票

评论者:alexmiller

希望对描述有更多的更新。我的问题是调用数据读取器函数是否应该返回 nil。有没有什么合理的用例需要这样做?看起来你正在使用读取器读取非 nil 标签值的描述,因此返回 nil 是令人困惑的。这不是可能的来回转换,因此看起来是不对称的。

0 投票
评论者:[email protected]

没有法律规定我是不能这么做的。我的简单例子是 {{#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]

我测试了这个补丁,并且它在我的当前主分支上工作得很好。我建议添加另一个测试来确认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 投票
...