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 提出

尼古拉,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 转变的趋势比有害要多得多。

0

评论由:mikera 提出

尼古拉,我并不反对使用显式的 :refer / :require,我也同意这是正常做法。明确是有好处的,我通常也会这样做(除了测试/演示代码之外)。

然而,我们现在的讨论并不是关于这个案例:这个问题更相关于用户(出于自己合理的理由)决定导入整个命名空间的情况。这通常很方便(例如,在 REPL 使用中),有时也有助于特定的目的(例如,测试)。

我就从库作者的视角来考虑这个问题:我希望用户能够以最方便的方式使用库(这可能包括导入所有变量),并且我不希望在我发布新版本时用户代码随机地出错。请注意,这也意味着我对用户代码没有控制权,因此任何涉及显式 requires、excludes 或其他手动工作方案的解决方案都不是实际可行的。

你可以说“这是他们的错”,但根据目前的情况,Clojure 现在有支持这种行为,我认为它应该平稳地工作。

0

由alexmiller发表的评论:

我认为库/演化的论点是很好的,并且我喜欢这一点,因为它减少了第三方库演化的破坏。我在 clojure.core 中对此有很强的感觉(它是自动引用的),在其他方面则没有那么强烈。

另一方面,如果我们去掉这个错误,我们应该明确我们放弃了什么,以全面考虑它。我们至少是在偶然覆盖时放弃了有用的错误。还有其他的影响吗?

我不希望我们在1.7中改变任何事情。

0

评论者:stu

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

能否提供一个反映命名空间的宏,而无需更改核心即可满足此用例?

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