Fork me on GitHub
#clojure-spec
<
2020-11-05
>
Jim Newton17:11:17

I just discovered that the following doesnt work.

(ns some-ns
  (:require [clojure.spec.alpha :as s]))

(defn foo []
  (= (resolve 's/*) (resolve 'clojure.spec.alpha/*)))
because when foo gets called by the application, the name space might not have required [clojure.spec.alpha :as s] Instead, I did the following and it seems to work.
(ns some-ns
  (:require [clojure.spec.alpha :as s]))

(defn foo []
  (binding [*ns* (find-ns 'some-ns)]
    (= (resolve 's/*) (resolve 'clojure.spec.alpha/*))))

andy.fingerhut17:11:44

You get different results than this in a REPL?

user=> (require '[clojure.spec.alpha :as s])
nil
user=> (resolve 's/*)
#'clojure.spec.alpha/*
user=> (resolve 'clojure.spec.alpha/*)
#'clojure.spec.alpha/*
user=> (= (resolve 's/*) (resolve 'clojure.spec.alpha/*))
true

andy.fingerhut17:11:20

Note that you have no * after clojure.spec.alpha/ I do not know if that is a typo in chat, or reflects your actual code.

Jim Newton17:11:41

yes a copy/paste error. corrected, should be /* everywhere

andy.fingerhut17:11:41

Now I see clojure.spec.alpha. Did you intend to use clojure.spec.alpha/* instead?

andy.fingerhut17:11:48

defn foo is in the namespace some-ns ? If so, how does some part of your code call foo without first require'ing some-ns ?

Jim Newton17:11:00

important observation is that the behavior of resolve depends on the value of *ns* when foo is called, not when foo is defined.

Jim Newton17:11:57

the caller of foo has required some-ns, but he might not have aliased closure.spec.alpha to s

andy.fingerhut17:11:06

Got it. Yes, that is true, and resolution of aliases like s definitely depends upon the namespace in which they are resolved.

Jim Newton17:11:25

i found out because I ran my tests from the repl where I had required spec and aliased to s. But when I tested from lien test at the comand line, it ran the tests with the user namespace, which I never tested in.

andy.fingerhut17:11:31

Alias s could be not an alias in some namespace, be used for clojure.spec.alpha in another namespace, and be used for clojure.set in yet another namespace. Not recommended for developer sanity to use the same alias for different namespaces, but Clojure allows it.

Jim Newton17:11:37

besides, when I develop the code, I use some convention. But I don't impose that convention on my customers who might have very different programming styles. or they theoretically might even be calling my code from java or some such

andy.fingerhut17:11:59

The doc string for resolve gives a pretty strong hint about this dependence upon the current value of *ns*

Jim Newton17:11:04

I think all calls to resolve or suspect within code.. I'm thinking of refactoring every call in my program and replacing with ns-resolve so I'll have to think about which ns to use. Then test from repl and also from lein command line as a general pratice

Jim Newton17:11:24

it's on my to-do list.

andy.fingerhut17:11:45

Using ns-resolve instead of resolve sounds like a good idea, if you want to force yourself to be explicit about in which namespace the resolving is performed.

Jim Newton17:11:39

of course nothing prohibits me from using (ns-resolve *ns* foo) if that's the appropriate one to use.