Fork me on GitHub

@alexmiller Thanks for the quick answers. Explained: If the answer is "you need a separate namespace per data type with colliding keywords", so be it.... just wanted to have the discussion.


@eriktjacobsen Yes, the answer is to provide unique namespace-qualifiers for each of the colliding keywords -- remember that those namespaces do not have to exist, but they should have names that represent the different concepts being modeled.


The whole point of namespaces is to provide unique ways to name things that are distinct (but otherwise have the same unqualified name).


Right, it's just unfortunate to lose the relationship of between using the spec and knowing where it's defined, losing ability to use the :: and aliases (until patched), and other limitations mentioned. I understand that might be the answer, its just my team is unhappy if that's the final answer.

gfredericks01:10:35 is a valid keyword I think


I don't suppose it's likely to make anybody happy though


Correct, but when used in a (spec.keys :req-un) it will require the keyword to be :baz.hullabaloo, correct? Rather than :hullabaloo. That is basically the same solution as my first proposal, just with . instead of /


yep. it's just sadness all over


it does seem like differentiation between specspace and namespace seem slightly confused, or dare I say complected.


OTOH it would be weird and confusing to have many parallel namespace systems e.g. those lisps that keep functions separate from the other kind of thing


Why use :req-un for a namespaced key?


Because the incoming data I'm trying to spec is generally using unqualified keys. Such as from parsing json.... I suppose I could add a step before doing spec validation that transforms all the unqualified keys into qualified keys using some mapping scheme, validates with spec, then unqualifies them again for usage downstream, but that's basically the functionality i'm looking for from spec and seems like a lot of overhead


Ah, okay. It sounded like you had control over the keyword. That makes sense though.


@eriktjacobsen FWIW, I am struggling with similar issues. I tried (briefly) using spec keywords in "fictional" namespaces (e.g. not corresponding to clojure ns), but then I end up with an explosion of long namespaced keywords. Lots of typing, lots of things to read and process when looking at code. The :: really helps in reducing that.


Somewhat related: I'm also thinking about dropping :req-un and moving to fully-qualified keys everywhere. But there is a price to be paid in storage (JSON database), transmission (websocket trafic isn't compressed, Transit helps but I'm not sure to what extent), code complexity (need to include keyword namespaces in all destructuring code), and ClojureScript code building keywords from strings. I'm not sure what that price is.


if you throw in some utils it's not so bad


i use a macro that creates "relative" aliased ns and tend to spec maps using it following a pattern like ::map ::map/foo ::map/bar ::map/baz etc


(defmacro rel-ns [k] `(alias k (create-ns (symbol (str ns "." (str k))))))


you can just do (rel-ns ' if deeply nested and then use it as, it's quite readable imo


Thank you! We have thought of similar workarounds, mostly wanted to bring the discussion up for a solution from the core.specs team, though we could incorporate this if we have to workaround it.


Hi! Given ::allowed-val "enum spec", is there a way to print all the allowed values in the error message? Currently it prints (into #{} allowed-vals). And let's consider it's the requirement that I need allowed-vals extracted as a var because I need to iterate over it in other places.

(def allowed-vals [1 2 3])
(s/def ::allowed-val (into #{} allowed-vals))
(s/explain ::allowed-val 5)

val: 5 fails spec: :cljs.user/allowed-val predicate: (into #{} allowed-vals)
:cljs.spec.alpha/spec :cljs.user/allowed-val
:cljs.spec.alpha/value 5


user=> (s/def ::foo #{:a :b :c})
user=> (s/form ::foo)
#{:c :b :a}
user=> (doseq [i (s/form ::foo)] (prn i))


yeah, it's a bit backwards but should work, thanks


There is no forwards or backwards with a set, right? Unordered.


right 🙂 I meant that it's backwards in a sense that I'd like the variable to be the source of allowed values instead of putting them into spec


and what if the enum values cannot be hardcoded like that in spec? e.g. when I need to read them from file


right now calling eval to build specs is probably the best choice, but work is apparently underway on making spec more "programmable" -- make specs from external stuff


how would I spec a function with variadic keyword args like (myfn :a 1 :b 2)? I’m trying to use (spec/* (spec/keys :req-un [::a ::b])) but that’s not right


ah thanks


Can somebody help me out with writing a fdef for a multi-method using defmulti?


I might be able to in a little while. Do you have an example?


I have a function which takes 2 maps as input and returns a vector with 2 maps.

defmulti my-function (fn [map1 map2] (:type map2)

defmethod my-function :type1
  [map1 map2]
  (let .... 
[ret-map1 ret-map2]

defmethod my-function :type1
[map1 map2]


This is what I tried for fdef -

(s/fdef my-function
             :args (s/cat :map1 map? :map2 map?)
             :ret    vector?)


Not sure exactly what’s not working but this works for me:

(defmulti my-function (fn [map1 map2] (:type map2)))
(defmethod my-function :type1 [map1 map2]
  [map1 map2])
(defmethod my-function :type2 [map1 map2]
  [map2 map1])
(s/fdef my-function
        :args (s/cat :map1 map? :map2 map?)
        :ret vector?)
(stest/instrument `my-function)


So how do I test the dispatch-value of the dispatch-fn in the defmulti definition?