Reputation: 5924
When I require a namespace inside a clojure-script source file, I can use it afterwards in the code.
E.g:
(ns my.core
(:require [mylib.core :as lib]))
(lib/my-f)
(def something 99)
However, when I try to call (lib/my-f)
inside the repl - after changing the namespace via (ns my.core)
- I cannot access it. In contrast, all other definitions inside the ns are acessible: like something
from the example above.
Is there a way to access the requirements in the repl? Or do I have to require them manually in the repl every time? This would be very tedious of course.
Upvotes: 7
Views: 5515
Reputation: 3527
If you use ns
to change namespace in a ClojureScript REPL, this sets the namespace aliases to match those used in the ns
form.
Here is an example illustrating the concept:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))
foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)
bar.core=> (ns foo.core)
foo.core=> (string/starts-with? "abc" "a")
WARNING: No such namespace: string, could not locate string.cljs, string.cljc, or Closure namespace "" at line 1 <cljs repl>
WARNING: Use of undeclared Var string/starts-with? at line 1 <cljs repl>
ReferenceError: "string" is not defined
If instead you use the in-ns
REPL special to change to an existing namespace, this will preserve aliases:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (ns foo.core (:require [clojure.string :as string]))
foo.core=> (string/starts-with? "abc" "a")
true
foo.core=> (ns bar.core)
bar.core=> (in-ns 'foo.core)
nil
foo.core=> (string/starts-with? "abc" "a")
true
An interesting related aspect: If you use require
, it will, under the hoods, employ an ns
form with special meta baked into the form that preserves existing aliases:
$ clj -m cljs.main
ClojureScript 1.10.520
cljs.user=> (require '[clojure.string :as string])
nil
cljs.user=> (require '[clojure.string :as str])
nil
cljs.user=> (string/starts-with? "abc" "a")
true
cljs.user=> (str/starts-with? "abc" "a")
true
If you are curious, this is the :merge true
meta here: https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/repl.cljc#L679
and it is honored by the analyzer here: https://github.com/clojure/clojurescript/blob/r1.7.228/src/main/clojure/cljs/analyzer.cljc#L1953
By seeing how this works, it should provide some insight into why an ns
form evaluated directly in the REPL (without merge
meta) can lead to aliases being cleared.
In short, avoid directly using the ns
special to change to a namespace in the REPL. Instead use it to create a new namespace in the REPL while specifying any required namespaces.
Use the in-ns
REPL special to switch to an existing namespace. It can also be used to create a new namespace.
Use require
to load namespaces into the REPL, and then use in-ns
to switch to them.
Upvotes: 10
Reputation: 91857
As long as you require
the namespace before switching to it with ns
or in-ns
, this all should work fine. The puzzling thing to me is that something
is accessible, meaning your code was loaded: that should mean that its namespace form was evaluated too, and thus you should have its aliases available. Are you sure you did this from a fresh state, and didn't, say, define something
independently as well? Double-check by:
(require 'my.core)
(in-ns 'my.core)
something?
Can you still not access lib/my-f
? I predict that one of those two things will change: you should be able to access neither, or both.Upvotes: 1