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 已经在命名空间 bar 中引用:#'foo/a,编译位置:(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 已经在命名空间 bar 中引用:#'foo/a

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

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

基本问题是当前的行为会导致用户代码在库升级添加新变量时崩溃,需要更改用户代码才能修复或绕过它。我认为这是破坏性的行为,至少是非常糟糕的设计。

尤其是因为我们被鼓励选择好名字:我从库编码规范中引用(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 使用),有时对于特定的目的很有价值(例如,测试)。

我主要从图书馆作者的角度关注这个问题:我希望用户能够以最方便的方式使用库(这可能包括导入所有变量),并且我不希望我的新版本发布时用户代码随机崩溃。注意,这也意味着我无法控制用户代码,所以任何涉及明确 requires、排除或其他手动解决方法的方案都不是实际可行的解决方案。

你可以说是“这是他们的错”,但当前 Clojure 的确应该支持这种情况,所以我认为应该正常工作。

0

评论人:alexmiller

我认为库/演化的论点是好的,我喜欢因为这样就减少了第三方库演化的破坏性。(我在 clojure.core 自身对此感受非常强烈,它自动引用,其他情况则不那么强烈。)

另一方面,如果我们去掉这个错误,我们应该明确我们正在放弃什么,以便充分考虑。显然,我们至少放弃了一个在意外覆盖的情况下发生的有用错误。还有其他影响吗?

我不期望在1.7中做出任何更改。

0

评论者:stu

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

是否可以通过一个反映命名空间的自定义宏来满足这种用例而不需要更改核心?

0
参考:https://clojure.atlassian.net/browse/CLJ-1401(由mikera报告)
...