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

欢迎!请查阅 关于 页面了解有关此工作方式的更多信息。

+1 投票
错误

`
=> (ns foo)
nil
=> (def a 1)

'foo/a

=> (ns bar (:require [foo :refer :all]))
nil
=> (def a 2)
编译器异常 java.lang.IllegalStateException: a 已经引用了: #'foo/a 在命名空间: bar,编译:(NO_SOURCE_PATH:4:1)

clojure.lang.Compiler.analyzeSeq (Compiler.java:6745)
clojure.lang.Compiler.analyze (Compiler.java:6529)
clojure.lang.Compiler.analyze (Compiler.java:6490)
clojure.lang.Compiler.eval (Compiler.java:6801)
clojure.lang.Compiler.eval (Compiler.java:6760)
clojure.core/eval (core.clj:3079)
clojure.main/repl/read-eval-print--7095/fn--7098 (main.clj:240)
clojure.main/repl/read-eval-print--7095 (main.clj:240)
clojure.main/repl/fn--7104 (main.clj:258)
clojure.main/repl (main.clj:258)
clojure.main/repl-opt (main.clj:324)
clojure.main/main (main.clj:422)

原因
IllegalStateException: a 已经引用了: #'foo/a 在命名空间: bar

clojure.lang.Namespace.warnOrFailOnReplace (Namespace.java:88)
clojure.lang.Namespace.intern (Namespace.java:72)
clojure.lang.Compiler$DefExpr$Parser.parse (Compiler.java:534)
clojure.lang.Compiler.analyzeSeq (Compiler.java:6738)
clojure.lang.Compiler.analyze (Compiler.java:6529)

`

我预计最坏的情况只能是类似的警告像初始命名空间加载时一样,而不是在这里抛出异常。

22 个回答

0 投票

评论由:bronsa

CLJ-1746 相关,并且我比 CLJ-1257 更喜欢这个建议

0 投票

评论由:mikera

您好,Nicola,CLJ-1746 看起来是一个合理的建议,但它仍然没有解决这里的问题,原因与 :exclude 一样(参见我对 Alex 的评论)

根本问题是当前的行为在库升级以添加新变量时会导致用户代码中断,需要更改用户代码以修复/解决此问题,我认为这是错误的行为,至少是很糟糕的设计。

尤其是因为我们被鼓励选择 good names:我从库编码标准(http://dev.clojure.org/display/community/Library Coding Standards)中引用

"使用好名字,并且不要害怕与其他命名空间中的名称冲突。这就是灵活的命名空间支持所在之处."

当用户代码不断中断时,它并不十分灵活...

0 投票

评论由:bronsa

从同一页面,向下两行
"对其他包的依赖要明确且简约。在1.4及以上,推荐使用:require :refer;在1.0-1.3之间,推荐使用:use :only。"

如果用户不小心导入整个包,我认为这是他们的责任。自从Clojure 1.3版本以来,普遍观点认为 :use/:refer :all 不是好主意,人们已经逐渐开始从这种做法中退出,更愿意使用 :require :refer 或 :require :as。

仍然使用 :use/:refer :all 的少数人,主要是因为向后兼容性或者是在测试中(我自己在 tools.reader 中出于这个原因这么做)。

我真的不认为这是一个像你所认为的那样糟糕的设计选择,我认为社区中的大多数人都会同意,当前的行为以及向使用 :require :refer/require :as 转变,比起使用 :use/:refer :all 来说,要更有益于有害。

0 投票

评论由:mikera

你好Nicola,我并不反对使用显性的 :refer / :require,并且我同意这是正常的做法。明确指出是好事,我通常也会这么做(除了在测试/演示代码中)。

然而,我们讨论的并不是那种情况:这个问题最相关的情况是用户出于自己的合法原因决定导入整个命名空间。这通常很方便(例如,在REPL中使用),有时对于特定目的来说也很有价值(例如,测试)。

我从库作者的角度关注这个问题,我希望用户能够在最方便的方式下使用库(这可能包括导入所有变量),并且我不希望当发布新版本时用户的代码突然出现问题。请注意,这也意味着我无法控制用户的代码,所以任何涉及显式要求、排除或其他手动解决方案的方法都不是实用的方案。

你能说“这是他们的责任”,但Clojure目前应该提供这种支持,我认为它应该能够正常工作。

0 投票

评论由:alexmiller 提出

我认为库/进化的论点是好的,我喜欢它减少了第三方库进化的故障。在这方面,我在 clojure.core 中感触很深,它现在是自动引用的,在其他方面的影响则较小。

另一方面,如果我们移除了这个错误,我们应该清楚地说明我们放弃了哪些东西才能充分考虑它。我们很可能至少放弃了一个在意外覆盖时发生的有用错误。还有其他影响吗?

我不期望在1.7版本中改变任何东西。

0 投票

评论者:stu

将问题重新分类为功能请求,因为当前行为是原始意图。

是否可以为这种使用场景提供一个反映命名空间的宏,而不需要改变核心?

0 投票
...