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而不是抛出异常。如果可能的结果是指令或记录的Java标识符开头,则进行理智的检查。对于特殊字符(而不是假设它是一个标记字面量),提供更好的错误信息。

0

评论由:[email protected]发布

clj-1138-data-reader-return-nil-for-no-op.patch 允许被视为无操作的nil返回值的数据读取器(类似于 #_)。对于一个读取器而言,nil 并不是一个正常的有用值(实际上,在Clojure 1.4到1.5 beta2版本中返回nil会导致异常)。通过这个补丁,可以使用数据读取器获得类似条件特性读取器的东西。

0

评论由:[email protected]发布

clj-1138-allow-data-reader-to-return-nil-instead-of-throwing.patch是第一个需要考虑的补丁。它仅仅允许数据读取器返回nil,并将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

如果您使用以下命令,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的最新版本中更改了一些空白字符。

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返回值要做特殊处理?如果按设计被认为是非法的,这个错误信息是否能启发用户?

在提交该bug时以及今天,我都找不到相关的记录性限制。所以这看起来像是一个简单的错误。数据读取项应该允许返回nil,Clojure读取器应该像通常一样处理它。我的临时措施是返回(quote nil),这给出了预期行为而没有触发bug。

0

评论由:alexmiller

希望看到更多的描述更新。我的问题是调用数据读取函数是否应该返回nil。有哪种合理的用例需要这样做吗?看起来你是在用读取器读取非nil标记字面值的描述,因此返回nil是令人困惑的。这不可能转圆形,因此似乎是不对称的。

0
评论由:[email protected]

“没有法律授权,就没有处罚”或基本上,除非你说它是非法的,否则我应该能够这样做。我的简单示例是 {{#C NULL}},这在对我来说显然是nil。

回顾这个问题,我可以看到大多数人认为标记字面是用于在Clojure字面值中编码外来值的方法。如果你只关心一个可扩展的数据表示法,谁还需要另一种写nil的方法呢?这是一个合理的问题。

我想使用数据读取器作为某种受限的读取宏(类似于Common Lisp中的使用)。我是在做一些特定平台的事情时发现这个错误的(在读取条件实现之前很久)。在我的情况下,在“其他”平台上返回nil很方便。

数据读取器的许多用法都不是双射的。例如,{{#infix (3 + 4)}} 解释为常量7的同样也不是可逆的。除非你是Dan Friedman或Wil Byrd,否则可逆性是一个困难的条件。:-)

我会尝试用更多上下文更新我的描述,但我不想因为我非传统的用法而分散人们对于显然的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
...