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而不是抛出异常。它会进行sanity检查,有关可能的标签或记录是JavaIdentifierStart(). 对于可能实际上是分发宏的特殊字符,它提供了更好的错误信息(而不是假设它是带标签的字面量)。

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)' 而不是 plain nil 来解决这个问题。这个表达式 Conveniently 评估为 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 日,并干净地应用于最新的 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,如果你能查看需要更新的内容,那就太好了。在 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。是否有好的用例需要这样做?看起来你正在用读取器读取非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,双向转换是一个艰难的要求。:-)

我将尝试更新我的描述,提供更多上下文,但我不想让任何人的注意力因我不寻常的使用而分散,从而忽视了 obvious bug(以及较差的错误信息)。
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
...