clojure-spec

About: http://clojure.org/about/spec Guide: http://clojure.org/guides/spec API: https://clojure.github.io/spec.alpha/clojure.spec.alpha-api.html
Jim Newton 2020-11-05T17:02:17.277600Z

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/*))))

2020-11-05T17:05:44.277700Z

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

2020-11-05T17:06:20.278Z

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 Newton 2020-11-05T17:06:41.278300Z

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

2020-11-05T17:07:41.278700Z

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

2020-11-05T17:08:48.279Z

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 Newton 2020-11-05T17:09:00.279200Z

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

Jim Newton 2020-11-05T17:09:57.279400Z

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

2020-11-05T17:10:06.279600Z

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

Jim Newton 2020-11-05T17:11:25.279800Z

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.

2020-11-05T17:11:31.280Z

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 Newton 2020-11-05T17:12:37.280200Z

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

2020-11-05T17:12:59.280400Z

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

Jim Newton 2020-11-05T17:14:04.280600Z

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 Newton 2020-11-05T17:14:24.280800Z

it's on my to-do list.

2020-11-05T17:15:45.281Z

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 Newton 2020-11-05T17:17:39.281200Z

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