2024 Clojure状态调查!分享你的想法。

欢迎!请参阅关于页面以了解如何工作的更多信息。

0
语法和读取器

当前,规范不允许包含多个斜杠的键和符号,但读取器允许。
这个微不足道的补丁也使得它们对读取器不可读。

前置

user=> :foo/bar/baz :foo/bar/baz

后置

user=> :foo/bar/baz RuntimeException Invalid token: :foo/bar/baz clojure.lang.Util.runtimeException (Util.java:221)

9 个答案

0

由 jafingerhut发表的评论:

这似乎与 CLJ-1527 相重叠?

0

由 zamaterian发表的评论:

请注意,跨 Clojure 版本 1.5 和 1.6,具有多个斜杠的键的哈希值不同

这会在使用与 Clojure 1.5 兼容的 datomic 版本并在 Clojure 1.6 下运行时创建问题,并且模式中有一个或多个包含多个斜杠的键。

0
_由 zcaudate 发表的评论_

请考虑以下原因重新考虑此“修复”:

- (keyword "foo/bar/baz") 也需要修复,以保持一致性
- 它将破坏我的代码的用户
   - http://docs.caudate.me/adi/adi-guide.html
   - http://docs.caudate.me/adi/adi-walkthrough.html#schoolyard

请参阅下面关于此主题的讨论。


dm3 [17:04]
为什么`(read-string "a/b/c")`可以,而`(clojure.tools.reader/read-string "a/b/c")`却会失败并显示`Invalid token`错误呢?

hiredman [17:04]
有一个修复read-string的票据

dm3 [17:05]
因此正确的行为是让它失败吗?

hiredman [17:05]
http://dev.clojure.org/jira/browse/CLJ-1530

dm3 [17:06]
谢谢,看来这是一个破坏性的改变:simple_smile

hiredman [17:07]
文档已经阻止了一些时间像a/b/c这样的符号,而这些不确定符号的读取行为显然在某个时刻有所改变

lucas [17:09]
加入了#clojure

zcaudate [17:16]
@hiredman:说真的,我真的很生气,因为我一直在使用`:a/b/c`关键字...甚至写了一个完整的库来处理这个问题 http://docs.caudate.me/hara/hara-string.html#api---path (已编辑)

[5:16]
现在他们正在将其取消

[5:18]
我认为应该首先移除`::foo/baz`这样的关键字

[5:20]
 ```user=> (require '[clojure.walk :as walk])
nil
user=> ::walk/hello
:clojure.walk/hello
```

[5:20]
这会引发很多问题

[5:20]
特别是与分析器相关的

[5:22]
https://github.com/jonase/kibit/issues/14
 
GitHub
Kibit在处理带有别名的命名空间限定关键字时出错 · Issue #14 · jonase/kibit · GitHub
如果代码中包含带有别名的命名空间限定关键字,Kibit会报错并显示Invalid token异常。下面是一个展示这个问题的代码示例 - ;;; foo.clj (ns foo) ;;; bar.clj (n...

[5:25]
@dm3 如果确实存在问题,你可以修复它

[5:25]
https://github.com/helpshift/hydrox/blob/master/lein/src/leiningen/hydrox/setup.clj
 
GitHub
helpshift/hydrox
hydrox - 深入挖掘你的代码

dm3 [17:31]
是的,不幸的是,我不得不修复cljs.tools.reader也:confused

[5:31]
我打算只是绕过去

bronsa [17:36]
@zcaudate:`::foo/bar`风格的关键字是按照设计实施的,不会改变,而`:foo/bar/baz`根据规范一直是无效的,并且是没有定义的行为(已编辑)

[5:37]
@dm3:改变未定义的行为算不算破坏性改变:simple_smile

dm3 [17:37]
破坏性改变,意味着它破坏了人们的代码:simple_smile

[5:37]
比如zcaudate

bronsa [17:38]
如果它使用无效的Clojure,那么这段代码就已经是损坏的了。它只是偶然工作正常

dm3 [17:39]
我从实用主义的角度来看问题。从理论上说,你是对的:simple_smile

[5:40]
我不会做出评判

bronsa [17:40]
实用主义地说,`:foo/bar/baz`是一个即将发生的问题的BUG。`(namespace :foo/bar/baz)`返回什么?

dm3 [17:40]
目前返回的任何内容?

[5:41]
我的意思是,这有点依赖于实现

sveri [17:41]
@dm3 @bronsa 我不认为你从理论上说是对的。一旦足够多的人适应了损坏的代码,它就相当于某种类似于共识的法律,由双方在足够长的时间内接受。

bronsa [17:42]
对于`(keyword "foo/bar" "baz")`和`(keyword "foo" "bar/baz")`的`namespace`呢?

dm3 [17:43]
我同意目前实现的语义很混乱

[5:43]
但我的观点是,这仍然是一个破坏性的改变

[5:43]
这不是说它是一个“坏”的改变

[5:43]
这只是一个判断

bronsa [17:43]
@sveri: 我会同意你的观点,只要我们接受的未经定义的行为不会造成无法修复的语义。

[5:44]
这就是为什么例如,使以数字开头的符号非法的补丁被撤销了

[5:45]
它破坏了现有的代码,它没有造成奇怪的语义,所以它被撤销了。而`:foo/bar/baz`则不是这样

[5:45]
@dm3:你可能会说,修复任何 bugs 都会造成不兼容的修改,然后——人们可能依赖于那个 bugs。

dm3 [5:46 PM]
是的,我认为关键在于错误的副作用有多明显以及有多少人依赖于它。

bronsa [5:46 PM]
如果文档明确说明“你可以在符号中使用 *one* `/`”,那么如果你使用多于一个 `/`,你就是在写无效的 clojure,你应该预期它可能会出错(编辑)

dm3 [5:47 PM]
我真的没有考虑过在符号中使用多斜杠(也没有注意到文档),我已经使用 Clojure 三年多了。

[5:47]
我今天最初的想法是这是被允许的。

[5:47]
并且命名空间是第一个斜杠之前的第一个部分(编辑)

bronsa [5:51 PM]
但是,这并不合理。Clojure 中的 `/` 表示 `namespace separator`。不管 `FOO` 和 `BAR` 是什么,如果我看到 `FOO/BAR`,我知道 `FOO` 是命名空间,而 `BAR` 是名称。如果你想使用类似 @zcaudate 的库中的关键词来表达路径,你应该使用一个在 Clojure 中没有特殊意义的分隔符,比如 `.`(即 `:foo/bar/baz` -> `:foo.bar.baz` 或 `:foo/bar.baz`)(编辑)

dm3 [5:51 PM]
我不想争论语义学。只是在分享一个观点。

bronsa [5:52 PM]
我的观点是,实用主义观点(尤其是当它们与当前文档相矛盾时)只有在它们所暗示的语义明确且无歧义的情况下才应予以考虑。

sveri [5:53 PM]
@bronsa:很好的解释,谢谢 :simple_smile

dm3 [5:53 PM]
是的 :simple_smile

[5:54]
我同意这个,最终你必须做出决定。


zcaudate [9:07 PM]
@bronsa:书面形式的沟通往往会让人感觉到事情比实际情况要严重。

[9:08]
老实说……自从 1.6 版本的 edn 读者开始破坏我的代码以来,我就知道这会来了。

[9:09]
这可能更多是我的错,因为我没有早点沟通这个,但 oh well.. 我们都必须适应潮流

bronsa [9:09 PM]
@zcaudate:没问题,我只是因为你提到了你的库才用它做例子

zcaudate [9:10 PM]
话虽如此,你可以想象我的失望,因为我整个查询语义都是基于 `:foo/bar/baz` 特性(现在是 bug)上设计的(编辑)

[9:11]
http://docs.caudate.me/adi/adi-walkthrough.html#querying

[9:11]
你注意到我在我的文档中没有使用 `(adi/select ds {:student/classes/teacher/name "Mr. Blair"})`

[9:12]
,因为测试开始出错

jstew [9:12 PM]
@zcaudate:你发布了这么多高质量的东西,我 wonder 你是否从来都不睡觉!
1  

bronsa [9:12 PM]
@zcaudate:幸运的是修复应该很容易 :simple_smile: 只需用 `.` 代替 `/`

zcaudate [9:12 PM]
不对!

[9:13]
问题在于……datomic 有 `account.type/user` 这样的东西

[9:13]
所以我必须像 cljs 那样做 `account.type$user`

bronsa [9:13 PM]
(顺便说一句,这是高质量文档的例子,做得好)

zcaudate [9:14 PM]
@bronsa:hahaha 谢谢……也许你可以把修复应用到 1.10,这样我还可以多几个月的时间

[9:14]
这样我就不会出现太早的麻烦

[9:15]
就像这没什么大不了的……但我认为 `/` 调用的路径结构和映射嵌套之间有一个平行关系

[9:16]
因此有 `{:student {:classes {:teacher {:name '(?fulltext "Blair")}}

[9:17]
和 `{:student/classes/teacher/name "Mr. Blair"}`

[9:17]
在我看来这更简洁

bronsa [9:17 PM]
@zcaudate:很抱歉,这不是很清楚,但我实际上没有控制 clojure 中何时或什么是被加入的,我只是一个贡献者 :simple_smile: 因此 clojure/core 团队可能会做出不同的决定,实际上拒绝那个条目(如果我遇到这种情况,我会非常失望的!)如果那样发生,我无疑会修改 `tools.reader` 来允许它们也这样,(编辑)

zcaudate [晚上9:18]
@bronsa:真让人失望。

[9:19]
嗯……也许你可以强调这个事实

[9:19]
而且如果修复了,还需要对`(keyword "foo/bar/baz")`的修复(已编辑)

bronsa [晚上9:20]
我觉得这项工作永远也不会完成。对`keyword`/`symbol`等输入进行验证已经被问过/讨论过很多次,但出于性能原因一直被拒绝

zcaudate [晚上9:20]
所以这是一件关于一致性的事情。

bronsa [晚上9:20]
(尽管我不赞同这个决定,但似乎Rich不会在这个问题上改变主意)

[9:21]
@zcaudate:符号/关键字在运行时和有效读时符号/关键字之间存在区别

zcaudate [晚上9:21]
而且,这意味着我可以设置一个读取宏#k foo/bar/baz并得到相同的效果

[9:22]
虽然看起来有点丑,但我相信它将会起作用

bronsa [晚上9:23]
但关于`namespace`和`name`应该怎么处理的不确定性仍然存在,所以我不确定

[9:23]
@zcaudate:无论怎样都行不通,如果http://dev.clojure.org/jira/browse/CLJ-1530被接受,那么 neither `:foo/bar/baz` 也**不**会是有效的了

[9:24]
@zcaudate:顺便说一句,如果你强烈反对它,我建议你在这个条目中评论

新的消息
[9:25]
我 *怀疑* 响应将是“你应该使用一个在Clojure中没有特殊意义的分隔符”,但我可能完全错了(我发现核心团队并不经常同意我的意见 :)),特别是如果你指出你的库会崩溃。(已编辑)

zcaudate [晚上9:30]
@bronsa:感谢你提醒。我会留一个评论并求bdfl保佑。
0

评论者:alexmiller

Chris -

  • (keyword "foo/bar/baz") 仍然有效。可以为任何字符串创建程序性关键字 - 这比读者支持作为代码中的字面量的范围广泛得多,这是大家广泛使用的一个功能。在未来的某个时候,可能会为字符超出规范的符号或关键字提供一种转义机制,以便读者可以读取它们,但这超出了这个范围。
  • 你使用的关键字不符合 https://clojure.org/reference/reader,你不应该期望它们能工作。我认为你应该修改你的库。
0

评论者:zcaudate

Alex

  • 我不会一定称之为 非法,因为edn.reader中当前的行为是在1.6版本中添加的,没有警告。
  • 此外,如果 (keyword "foo/bar/baz") 被允许存在,那么仍然会存在@bronsa指出的不确定的命名空间/名称问题。我会为一致性而辩,如果 :foo/bar/baz 在读者中是非法的,那么它应该到处都是非法的。
  • 我的库应该没有问题... 但库的使用者可能需要更改他们的查询
0

评论者:alexmiller

阅读页面清楚地说明"'/'有特殊意义,它可以在符号中间使用一次来分隔命名空间和名称”,并且关键字“像符号”。这自从 internet archiver 上的我能找到的最古老的版本(2008年7月)以来就一直在阅读页面中。edn(尽管有其相似之处)与 Clojure 是不同的事物,并且是不相关的。

{{keyword}}的2个参数形式可以用无歧义的方式使用:(keyword nil "foo/bar/baz")。1个参数形式将根据第一个/拆分(在这个例子中拆分为"foo"和"bar/baz")。我看不出有任何理由需要更改这一点。

0

评论者:zcaudate

我不同意关键字中/的“特殊性”,尤其是如果它被允许作为字符串。

这导致另一个输出歧义问题

user=> (keyword "foo" "bar/baz")
:foo/bar/baz

user=> (keyword nil "foo/bar/baz")
:foo/bar/baz

除非输出显示为:foo//bar/baz,否则不清晰命名空间在哪里,并且如果输山不能作为数据读取回,则“code is data”的概念将被削弱。

还有符号的情况
user=> (symbol "foo/bar/baz")
foo/bar/baz

好... 至少所有列出的例子都是“非法”的

无论如何,即使文档没有明确说明这一点,:foo/bar/baz自从clojure开始以来就存在,并且个人而言,它似乎比符号更像字符串。讽刺的是,我很肯定我从我开始工作在 adi 时期阅读的 datomic 文档中学到了使用多个斜杠在关键字中 idea。

最终,决定不是我的,我确实重视 clojure 团队对语言发展的指导。但是,我确实希望我的意见能够被认可并考虑。

0

评论者:zcaudate

我将引用 Rich https://www.youtube.com/watch?v=P76Vbsk_3J0 @ 5:10

"许多你认为(与 lisp)问题是特性...长期..."

0
参考:https://clojure.atlassian.net/browse/CLJ-1530(由 bronsa 提交)
...