Welcome! Please see the About page for a little more info on how this works.

0 votes
in ClojureScript by

If you refer a var from another namespace, then you can def a new value for that var, and the def will mutate the other namespace, and other things will go wrong as illustrated in the example below.

FWIW, Clojure disallows this, and refuses to allow you to evaluate a def involving a referred var, and emits an error diagnostic like:

CompilerException java.lang.IllegalStateException: foo already refers to: #'some.name.space/foo in namespace: user, compiling:(NO_SOURCE_PATH:2:1)

Here is a complete example illustrating the issues:

Given:

`
(ns foo.core)

(defn square [x]
(* x x))
`

then do this in a REPL:

`
cljs.user=> (require '[foo.core :refer [square]])
nil
cljs.user=> (var square)

'foo.core/square

cljs.user=> (square 3)
9
cljs.user=> (ns-interns 'cljs.user)
{}
cljs.user=> (defn square [x] (+ x x))
WARNING: square already refers to: foo.core/square being replaced by: cljs.user/square at line 1

'foo.core/square

cljs.user=> (square 3)
6
cljs.user=> (var square)

'foo.core/square

cljs.user=> (in-ns 'foo.core)
nil
foo.core=> (square 3)
6
foo.core=> (in-ns 'cljs.user)
nil
cljs.user=> (ns-interns 'cljs.user)
{square #'cljs.user/square}
cljs.user=> (cljs.user/square 3)
TypeError: Cannot read property 'call' of undefined

at repl:1:105
at repl:9:3
at repl:14:4
at Object.exports.runInThisContext (vm.js:54:17)
at Domain.<anonymous> ([stdin]:41:34)
at Domain.run (domain.js:221:14)
at Socket.<anonymous> ([stdin]:40:25)
at emitOne (events.js:77:13)
at Socket.emit (events.js:169:7)
at readableAddChunk (_stream_readable.js:146:16)

cljs.user=> #'cljs.user/square

'cljs.user/square

cljs.user=> @#'cljs.user/square
nil
`

5 Answers

0 votes
by
_Comment made by: mfikes_

The attached patch essentially turns the warning into an error for non-core names, throwing an exception that matches Clojure's.

Example:


$ script/noderepljs
ClojureScript Node.js REPL server listening on 49203
To quit, type: :cljs/quit
cljs.user=> (def map 3)
WARNING: map already refers to: cljs.core/map being replaced by: cljs.user/map at line 1 <cljs repl>
#'cljs.user/map
cljs.user=> (require '[clojure.set :refer [intersection]])
nil
cljs.user=> (def intersection 3)
clojure.lang.ExceptionInfo: intersection already refers to: #'clojure.set/intersection in namespace cljs.user at line 1 <cljs repl> {:file "<cljs repl>", :line 1, :column 1, :root-source-info {:source-type :fragment, :source-form (def intersection 3)}, :tag :cljs/analysis-error}
    at clojure.core$ex_info.invokeStatic(core.clj:4725)
    at clojure.core$ex_info.invoke(core.clj:4725)
    at cljs.analyzer$error.invokeStatic(analyzer.cljc:697)
...
0 votes
by

Comment made by: mfikes

Here is an example showing that it is (as was before), OK to define a Var that shadows a core Var:

`
$ script/noderepljs
ClojureScript Node.js REPL server listening on 57077
To quit, type: :cljs/quit
cljs.user=> (defn quot [s] (str "'" s "'"))
WARNING: quot already refers to: cljs.core/quot being replaced by: cljs.user/quot at line 1

'cljs.user/quot

cljs.user=> (quot "hello")
"'hello'"
cljs.user=> (cljs.core/quot 6 2)
3
`

0 votes
by

Comment made by: mfikes

CLJS-1558-2.patch rebaselines

0 votes
by

Comment made by: mfikes

CLJS-1558-3.patch rebaselines

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJS-1558 (reported by mfikes)
...