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中,包含多个正斜杠的关键字有不同的hashCode。

当使用兼容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]
为什么`(read-string "a/b/c")`可以工作,而`(clojure.tools.reader/read-string "a/b/c")`会因`无效标记`失败呢?

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 在命名空间 qualified 关键字上出错 · Issue #14 · jonase/kibit · GitHub
如果代码包含具有别名的命名空间 qualified 关键字,Kibit 就会因为无效令牌异常而出错。以下代码展示了问题 - ;;; 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]
是的,不幸的是,您还必须修复 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:你可以这样认为,修复任何错误都是破坏性变化 - 人们可能依赖于这个错误。

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

bronsa [下午5:46]
如果文档明确说明“你可以在符号中使用一个 `/`”,那么如果你使用多个,你就是在编写无效的 Clojure,你应该期待它可能会破坏(已编辑)

dm3 [下午5:47]
我真正没有想过,在 Clojure 的三年多时间里,一个符号中的多重斜杠问题(甚至没有注意到文档)

[5:47]
我最初的印象(今天)是,这是允许的

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

bronsa [下午5:51]
但是,这并没有什么意义。在 Clojure 中,`/` 代表 `namespace separator`。无论 `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]
yep: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` 关键字特性设计了一个完整的查询语义(现在是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:幸运的是,修复应该很容易: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:抱歉如果这个解释不够清楚,但我实际上没有任何控制权,我只是一个贡献者: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 [21:21]
此外,这意味着我可以设置一个读取宏 #k foo/bar/baz,并得到相同的效果

[9:22]
它是愚蠢的丑陋,但我相信它会起作用

bronsa [21:23]
但是关于 `namespace` 和 `name` 的歧义仍然存在,所以我也不知道怎么办

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

[9:24]
@zcaudate:顺便说一句,如果你强烈反对这个条款,我建议你在那里留下一个问题评论

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

zcaudate [21:30]
@bronsa:谢谢你提醒。我会留下一个评论,并祈求 bdfl
0
by

评论者:alexmiller

Chris -

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

评论者:zcaudate

Alex

  • 我不一定会称之为 非法,因为在 edn.reader 中,1.6 版本新增了这种行为而没有警告。
  • 另外,如果 (keyword "foo/bar/baz") 被允许存在,那么 @bronsa 强调的命名空间/名称的不确定性仍然存在。我会为一致性而争辩,如果 :foo/bar/baz 在读取器中被视为非法,那么它应该到处都非法。
  • 我的库应该没问题... 但库的使用者可能需要更改他们的问题。
0
by

评论者:alexmiller

阅读页明确指出“/”有特殊含义,它可以用于符号中间,将命名空间与名称分开,并且关键字类似于符号”。这一条自2008年7月我在互联网档案馆找到的最早版本就已存在。edn(尽管与其相似)是Clojure之外的东西,与之无关。

{{keyword}}的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)
...