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

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

0
语法和读取器

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

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

user=> :foo/bar/baz RuntimeException 无效令牌::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 [5:04 PM]
为什么`(read-string "a/b/c")`可以正常使用,而`(clojure.tools.reader/read-string "a/b/c")`会报`Invalid token`错误呢?

hiredman [5:04 PM]
有一个修复`read-string`的工单

dm3 [5:05 PM]
所以正确的做法是让它出错吗?

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

dm3 [5:06 PM]
谢谢,看起来这是一个打破现状的改变:微笑

hiredman [5:07 PM]
文档中已经防止使用像`a/b/c`这样的符号名称一段时间了,而这些未指定符号的读取行为在某个时间点似乎发生了变化

lucas [5:09 PM]
加入了#clojure

zcaudate [5:16 PM]
@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 [5:31 PM]
是的,不幸的是,我必须修复cljs.tools.reader也能用的代码:困惑

[5:31]
我会只是绕过这个问题

bronsa [5:36 PM]
@zcaudate:`::foo/bar`这样的关键字是按照设计添加的,不会去掉,`:foo/bar/baz`根据规范始终是无效的,并且是未定义的行为(编辑)

[5:37]
@dm3:改变未定义的行为是打破现状的改变吗?微笑

dm3 [5:37 PM]
打破现状是指打破他人的代码:微笑

[5:37]
例如,zcaudate

bronsa [5:38 PM]
如果它使用无效的Clojure语法,那么代码已经是错误的了。它只是偶然在工作

dm3 [5:39 PM]
我从实用主义的角度来看这个问题。在理论上你是正确的:微笑

[5:40]
但我没有进行评判

bronsa [5:40 PM]
实用主义上,`:foo/bar/baz`是一个等待发生的错误。请问`(namespace :foo/bar/baz)`返回什么?

dm3 [5:40 PM]
目前,它返回什么就返回什么?

[5:41]
我的意思是,它的定义取决于实现

sveri [5:41 PM]
@dm3 @bronsa 我不认为你理论上是对的。一旦足够多的人适应了错误的代码,它就会陷入一种像普通法一样的东西,在双方之间被接受并持续了足够长的时间。

bronsa [5:42 PM]
那么关于`(keyword "foo/bar" "baz")`和`(keyword "foo" "bar/baz")`的`namespace`函数呢?

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

[5:43]
但我的观点是这仍然是一个打破现状的改变

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

[5:43]
这是一个判断问题

bronsa [5:43 PM]
@sveri:  我会同意你的说法,只要我们接受的未定义行为不导致无法修复的语义。

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

[5:45]
因为打破了现有代码,它没有导致奇特的语义,所以它被回滚了。然而,`:foo/bar/baz`的情况并非如此

[5:45]
@dm3:你可以提出一个观点,修复任何错误都是打破现状的改变 - 人们可能会依赖于这个错误。

dm3 [5:46 PM]
是的,我想重要的是错误的明显程度以及依赖该错误的人的数量。

bronsa [下午5:46]
如果文档明说“你可以在符号内使用 **一个** `/”,那么如果你使用超过一个,那么你编写的Clojure是无效的,你应该预期它可能会出错(编辑)

dm3 [下午5:47]
我甚至在用了Clojure三年多的时间内从没考虑过符号中的多个斜杠(也没注意到文档)

[5:47]
我今天最初的想法(今天)是它被允许的

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

bronsa [下午5:51]
不过,这没什么意义。Clojure中的`/`代表`命名空间分隔符`。不管`FOO`和`BAR`是什么,如果我看到`FOO/BAR`,我就知道`FOO`是命名空间,`BAR`是名称。如果你想在关键词中表达路径,例如在@zcaudate的库中那样,你应该使用一个没有在Clojure中有特殊含义的其他分隔符,比如`.`(即`:foo/bar/baz` -> `:foo.bar.baz`或`:foo/bar.baz`)(编辑)

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

bronsa [下午5:52]
我的观点是,如果它们隐含的语义是清晰且无歧义的,那么只有实用主义观点(特别是当它们与当前文档相反时)才应该被考虑

sveri [下午5:53]
@bronsa: 很好的解释,谢谢:微笑

dm3 [下午5:53]
yep:微笑

[5:54]
我同意这一点,因为最终你必须做出决定


zcaudate [晚上9:07]
@bronsa: 书面沟通有时会让人显得过于严肃

[9:08]
说实话…我从Clojure 1.6开始就知道会有事情发生,因为EDN读取器开始破坏我的代码

[9:09]
可能应该是我的责任,因为我没有早点传达这个信息,但无论如何…我们都要与时俱进

bronsa [晚上9:09]
@zcaudate: 没关系,我只是把你提到的库作为例子

zcaudate [晚上9:10]
说到这里,你可以想象我是多么失望,因为我已经基于`: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]
@zcaudate: 你发布了这么多高质量的内容,我怀疑你是否睡觉!
1  

bronsa [晚上9:12]
@zcaudate: 幸运的是,修复应该是简单的:微笑: 只要将`/`替换为`.`

zcaudate [晚上9:12]
不!

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

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

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

zcaudate [晚上9:14]
@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]
@zcaudate: 对不起,如果这不清晰,但我不实际控制Clojure的决定,我只是个贡献者:微笑: 所以有机会Clojure/core团队会做出不同的决定,并实际上拒绝那个ticket(如果这样我会非常失望!)。  如果那样发生,我显然会修改`tools.reader`以允许它们,(编辑)

zcaudate [晚上9:18]
@bronsa: damn。

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

[9:19]
并且,如果进行了修复,还需要修复`(keyword "foo/bar/baz")`(编辑)

bronsa [晚上9:20]
我觉得这永远也做不完。验证 `keyword`/`symbol` 等输入已被讨论过无数次,但出于性能考虑一再被拒绝

zcaudate [晚上9:20]
所以这是一个一致性问题。

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

[9:21]
@zcaudate:一个符号/keywords在运行时可使用的内容和有效的读取时间符号/keywords是有区别的

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
by

评论由:alexmiller 提出

Chris -

  • (keyword "foo/bar/baz") 仍然可以正常使用。可以为任何字符串创建程序性关键词 - 这比读取器支持的代码中的字面值要广泛得多,这是一个广泛使用的功能。在未来的某个时刻,可能会有一个转义机制,用于处理符号或关键字中的字符,以便读取器也可读取它们,但这超出了本讨论的范围。
  • 你的API使用了根据 https://clojure.org/reference/reader 规范非法的关键词,你不应该期望它们能够正常工作。我认为你应该改变你的库。
0
by

评论由:zcaudate 提出

Alex

  • 我不认为这是一个非法的行为,因为在 edn.reader 中添加这种行为是在1.6版本中,没有任何警告的情况下。
  • 此外,如果 (keyword "foo/bar/baz") 被允许存在,那么仍然存在@bronsa指出的不可确定的命名空间/名称问题。我会主张一致性,如果:foo/bar/baz在读取器中是非法的,那么它应该在所有地方都非法
  • 我的库应该没问题...但是,库的用户可能需要更改他们的查询
0

评论由:alexmiller 提出

读者页面明确表示“'/' 有特殊含义,它可以在符号中间使用 一次 来区分命名空间和名称”,且关键词“像符号”。这种描述在互联网档案馆中最古老的版本(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 文档中获得了使用多个斜杠的关键词的想法。

最终的决定不是由我来做的,我确实重视 clojure 团队对于语言发展的指导。然而,我确实希望我的保持现状的观点能够得到认可并被考虑。

0

评论由:zcaudate 提出

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

"你考虑到的许多问题(关于 lisp)都是特性...在将来..."

0
参考: https://clojure.atlassian.net/browse/CLJ-1530 (报告人:bronsa)
...