请在 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 已经在 namespace: 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 已经在 namespace: 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)

`

我原本期望(最坏的情况)在这里得到一个与初始 namespace 加载时相似的警告,而不是异常。

22 回答

0

评论由:alexmiller 提供

您能否提供一个更好的可复现测试用例,这个测试用例不依赖于 core.matrix?同时,请包括发生时的 (pst **e)。

0

评论由:jafingerhut 提供

我已经尝试了最小的 Leiningen 项目,看一下是否会产生重新定义的警告,以查看是否可以引发异常。使用命令 'lein new try1' 来创建项目骨架,然后编辑 src/try1/core.clj 以包含以下函数定义

`
(defn merge
"此 merge 的定义替换了 clojure.core/merge"
[x y]
(- x y))

(defn
[x y]
(
x y))
`

然后使用 'lein repl' 启动一个 REPL,然后我看到这种行为

用户=> (require '[try1.core :as c]) 警告:merge 已在命名空间: try1.core 中引用: #'clojure.core/merge,将被替换为: #'try1.core/merge 警告:* 已在命名空间: try1.core 中引用: #'clojure.core/*,将被替换为: #'try1.core/* nil 用户=> (require '[try1.core :as c] ) nil 用户=> (require '[try1.core :as c] :reload) 警告:merge 已在命名空间: try1.core 中引用: #'clojure.core/merge,将被替换为: #'try1.core/merge 警告:* 已在命名空间: try1.core 中引用: #'clojure.core/*,将被替换为: #'try1.core/* nil

这似乎是预期的行为,我没有看到Mike报告的异常。

看起来在Counterclockwise中使用Ctrl+Alt+L可能与(require ... :reload)有不同的操作,或者Mike的命名空间在重新定义clojure.core中的名称之外还有其他不同之处,这导致了问题。

0

评论由:alexmiller 提供

目前将其标记为NR - 乐于看到它重新打开,附有易于复现的测试用例。

0

评论由:mikera 提出

重现方法:

(ns op)
(defn (link: a b) (clojure.core/ a b)) ;; 给出警告
(ns use-op (:require (link: op :refer :all))) ;; 给出警告
(ns use-op (:require (link: op :refer :all))) ;; 给出错误!

我认为Counterclockwise仅通过CTRL-Alt+L重新加载命名空间,这导致了ns语句被重新执行。

文档字符串暗示ns可以使用多次(将“ns”设置为名为name(未求值)的命名空间,如果需要则创建它)因此我确实预期多次调用ns不会产生任何操作

0

评论由:alexmiller 提供

与CLJ-1578重复。

0

评论由:mikera 提出

这仍然困扰着我,并影响了core.matrix的最新版本,我不知道这是回归还是不是,但它在1.7.0-RC1中确实发生了。

我们能否为1.7修复这个问题?由于这个问题导致代码失败并强制重构用户代码(我的用例是向clojure.core.matrix命名空间添加新变量,用户代码中之前定义了同名变量,编译器报错),这真的很烦人。

0

评论由:mikera 提出

关闭此问题,我认为相关的bug报告中已经更好地处理了这个问题。

0

评论由:mikera 提出

重新开启这个问题,因为显然 CLJ-1578 并没有解决这个问题,它仅覆盖了 clojure.core 中的 vars。

我希望这个问题能够得到解决,不仅仅是在 clojure.core 中。

0
_评论者:mikera_

复现步骤

=> (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:1:1)
=> *clojure-version*
{:major 1, :minor 7, :incremental 0, :qualifier "RC1"}

堆栈跟踪

编译器异常:java.lang.RuntimeException:在本上下文中无法解析符号:pst,编译器位置:(NO_SOURCE_PATH:1:1)
    clojure.lang.Compiler.analyze (Compiler.java:6543)
    clojure.lang.Compiler.analyze (Compiler.java:6485)
    clojure.lang.Compiler$InvokeExpr.parse (Compiler.java:3737)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:6735)
    clojure.lang.Compiler.analyze (Compiler.java:6524)
    clojure.lang.Compiler.analyze (Compiler.java:6485)
    clojure.lang.Compiler$BodyExpr$Parser.parse (Compiler.java:5861)
    clojure.lang.Compiler$FnMethod.parse (Compiler.java:5296)
    clojure.lang.Compiler$FnExpr.parse (Compiler.java:3925)
    clojure.lang.Compiler.analyzeSeq (Compiler.java:6731)
    clojure.lang.Compiler.analyze (Compiler.java:6524)
    clojure.lang.Compiler.eval (Compiler.java:6789)
原因
RuntimeException 无法在这个上下文中解析符号:pst
    clojure.lang.Util.runtimeException (Util.java:221)
    clojure.lang.Compiler.resolveIn (Compiler.java:7029)
    clojure.lang.Compiler.resolve (Compiler.java:6973)
    clojure.lang.Compiler.analyzeSymbol (Compiler.java:6934)
    clojure.lang.Compiler.analyze (Compiler.java:6506)
    clojure.lang.Compiler.analyze (Compiler.java:6485)

0

评论者:bronsa

正如我在 CLJ-1578 中已经评论的那样,我认为这不是一个错误,并且我认为应该拒绝这个工单。

覆盖非 clojure.core 的 var 总是(至少从 1.2 开始)会引发异常。

0

评论者:bronsa

Mike,可能将这个问题提出到clojure-dev ml中,以获取一些观点是合理的?

0

评论由:mikera 提出

如果您喜欢,可以将其重新分类为功能请求。

我仍然将其视为缺陷,因为我期望:refer :all能够正常运行。

无论如何,这个问题都破坏了我区域(数据科学/探索性统计分析/数据处理)的用户代码。使用/引用全部对于设置方便的命名空间进行探索性工作非常有用,因此我不接受强制用户明确引入每个变量的做法作为实用解决方案(如Nicola在CLJ-1578中建议)。

我还发现它在REPL中工作并重新加载命名空间时引起问题。

如果Clojure核心团队真的想保留这种令人讨厌的行为,我们至少能在库级别关闭它吗?或许可以在clojure.core.matrix命名空间中添加一些命名空间元数据来阻止这种触发?

0

评论者:bronsa

Mike,这只是我个人的观点,我不是核心团队的一员,也不代表他们,这也是为什么我建议你写clojure-dev ml。

此外,为了澄清,你报告的这个问题在重新加载命名空间时不会表现出来,因为异常是在重新定义发生时抛出来的。

0

评论由:alexmiller 提供

你可以用:exclude来解决这个问题

(ns bar (:require [foo :refer :all :exclude (a)]))

0

评论由:mikera 提出

嗨Alex,这当问题发生时可以作为修复,但并不能解决未来用户代码破坏的问题,除非用户能够准确预测将来可能会添加到"bar"中的符号。这又似乎给用户带来了不合理负担。

我大概是在主张,如果用户在自己的命名空间中定义了一个变量,那么他们就会乐意替换他们之前使用过的/引用过的任何命名空间中同名的变量。

如果用户真正担心不小心覆盖了东西,我将很高兴看到一个类似在替换时警告( warn-on-replace)的功能,这类似于 在反射时警告( warn-on-reflection)。我之前在 CLJ-1257 中提出了类似的想法,甚至写了一个补丁,用这种方式解决了整个问题。我们能在1.7中获取那个补丁或者类似的东西吗?

...