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.6兼容的Datomic版本,并在Clojure 1.5下工作时,以及模式中有一个或多个多于一个斜杠的键时创建问题。

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]
为什么`(read-string "a/b/c")`可以正常工作,而`(clojure.tools.reader/read-string "a/b/c")`却会因`Invalid token`失败?

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

dm3 [下午5:05]
所以正确的做法是让它失败?

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

dm3 [下午5:06]
谢谢,这似乎是一个破坏性的变化 :simple_smile

hiredman [下午5:07]
文档已经限制了一些时间前像a/b/c这样的符号,而这些未指定的符号的读取行为显然在某个时间段发生了变化

lucas [下午5:09]
加入了#clojure

zcaudate [下午5: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 (...

[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]
是的,不幸的是,我还得修复cljs.tools.reader :confused

[5:31]
我想我只是会解决这个问题

bronsa [下午5:36]
@zcaudate: `::foo/bar`风格的符号是由设计在那里,不会消失,`:foo/bar/baz`根据规范始终是无效的,并且是未定义的行为(已编辑)

[5:37]
@dm3:修改未定义的行为是不是一个破坏性的变化? :simple_smile

dm3 [下午5:37]
破坏性的是在破坏人们的代码上 :simple_smile

[5:37]
例如 zcaudate

bronsa [下午5:38]
如果使用了无效的clojure代码,这段代码就已经是错误的了。它只是意外地工作

dm3 [下午5:39]
我从实用主义的角度来看。理论上你是对的 :simple_smile

[5:40]
但我没有评判

bronsa [下午5:40]
在实践中,`:foo/bar/baz`是一个即将发生的错误。`(namespace :foo/bar/baz)`返回什么?

dm3 [下午5:40]
当前返回什么?

[5:41]
我的意思是,它有点由实现定义

sveri [下午5:41]
@dm3 @bronsa 我认为你们在理论上并不完全正确。一旦足够的人适应性错误的代码,它就类似于一个长期被双方接受的类似于习惯法的法

bronsa [下午5:42]
关于`(keyword "foo/bar" "baz")`和`(keyword "foo" "bar/baz")`的`namespace`是什么?

dm3 [下午5:43]
我同意当前的实现语义很混乱

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

[5:43]
并不是这个变化是“坏”的

[5:43]
这是一个判断

bronsa [下午5:43]
@sveri:  我同意你的观点,只要我们接受的未定义行为不会产生不可能修复的语义。

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

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

[5:45]
@dm3: 你可以争论修复任何bug都是破坏性的变化 - 人们可能依赖这个错误。

dm3 [下午5:46]
是的,我想重要的是错误的明显性和依赖它的人数

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:非常棒的说明,谢谢:simple_smile

dm3 [下午5:53]
是的:simple_smile

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


zcaudate [晚上9:07]
@bronsa:书写形式的交流往往会使事情显得比实际更严重

[9:08]
老实说… 我从 1.6 版本起就知道会这样,因为 EDN 读者开始破坏我的代码了

[9:09]
这可能是我的责任,因为我没有早点解决这个问题,但哦,我们都要适应时代的变化

bronsa [晚上9:09]
@zcaudate:没问题,我只是因为您提到了您的库才用它作为例子

zcaudate [晚上9:10]
话虽如此,您可以想象我的失望,因为我根据关键字 `:foo/bar/baz` 功能(现在是错误)设计了一个完整的查询语义(现在是一个错误)(已编辑)

[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:幸运的是,修复应该很容易:simple_smile:只需用 `.` 替换 `/` 即可

zcaudate [晚上9:12]
不!

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

[9:13]
所以我必须做 cljs 的事情 `account.type$user`

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

zcaudate [晚上9:14]
@bronsa:哈哈,谢谢… 所以也许你可以把修复推到 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 的何时何地,我只是个贡献者: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:无论如何,如果这个链接被接受,那么`:foo/bar/baz`和`foo/bar/baz`都将成为无效的。

[9:24]
@zcaudate:顺便说一句,如果你强烈反对它,建议你在此票证中留言。

新消息
[9:25]
我*猜想*回应将是“你应该使用一个在Clojure中没有特殊意义的分隔符”,但我可能完全错了(我发现核心团队并不经常同意我的观点 :)),尤其是如果你指出你的库会出错的话。(编辑后)

zcaudate [晚上9:30]
@bronsa:感谢提醒。我会留下评论,并为bdfl祈祷。
0 投票
by

评论者:alexmiller

Chris -

  • 关键字`("foo/bar/baz")`仍然可以正常使用。可以为主机字符串创建程序性关键字,这比读者支持的代码中的字面量要广泛得多,这是一个广泛使用的特性。在未来某个时候,可能会为具有规范外字符的符号或关键字提供转义机制,使得读者可以读取它们,但这超出了本讨论的范围。
  • 您的API使用的是非法关键字,根据这个链接,您不应该期望它们能够工作。我认为您应该更改您的库。
0 投票
by

评论者:zcaudate

Alex

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

评论者:alexmiller

阅读页面明确指出"'/'具有特殊含义,它可以在符号中间使用一次,用于将命名空间与名称分开”并且关键词是“像符号一样”。这在我从互联网档案馆找到的最早版本中一直存在(2008年7月)。

可以使用关键词的2个参数形式不产生歧义:{{(keyword nil "foo/bar/baz")}}。1个参数的形式将根据第一个'/'进行分割(在本例中分解为"foo"和"bar/baz")。我认为没有必要改变这一点。

0 投票
by

评论者:zcaudate

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

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

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

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

除非输出显示为:foo//bar/baz,否则不清楚命名空间在哪里,如果输出无法作为数据恢复,则“代码是数据”的概念将减弱。

也存在符号的情况
user=> (symbol "foo/bar/baz")
foo/bar/baz

嗯...列出的所有例子都是一致的“非法”

无论如何,即使文档没有明确说明这一点,:foo/bar/baz自从Clojure开始以来就存在了,我个人认为它更像是字符串似的,而不是符号似的。讽刺的是,我确信我是从当初开始工作于adi时阅读的datomic文档中得到了使用多个斜杠的关键词的想法。

最终,决定权不在我这里,我确实重视Clojure团队在语言发展中的指导。然而,我确实希望我的论点可以保持现状能够得到认可并得到考虑。

0 投票
by

评论者:zcaudate

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

"你认为是问题(关于lisp)的许多东西实际上是功能...进而..."

0 投票
by
参考:https://clojure.atlassian.net/browse/CLJ-1530(由 bronsa 报告)
...