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

欢迎!请参阅 关于 页面以了解更多有关如何使用本站的信息。

+1
语法和读取器

如果 data-reader 返回 nil,则读取器抛出 java.lang.RuntimeException: No dispatch macro... 错误消息意味着标签的第一个字符没有任何分发宏。

以下是一个简单的示例

`
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 而不是抛出异常。进行可能的标签或记录的 sanity 检查。为特殊字符提供了更好的错误信息,这些特殊字符可能是分发宏(而不是假设它是标签字面量)。

0

评论由:[email protected] 发布

clj-1138-data-reader-return-nil-for-no-op.patch 允许将数据读取器返回的nil当作无操作(no-op)处理(类似于 #_)。对于数据读取器返回来说,nil并不是一个有用的值(实际上,在Clojure 1.4到1.5 beta2之间返回nil会导致异常)。使用这个补丁,你可以通过数据读取器获得一个类似条件功能读取器的结果。

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) 而不是 plain 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 仍然可以干净地应用到最晚的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
...