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
Aron 2020-04-22T01:08:36.235300Z

should spec have their own ns an import app ns? or should the app import the spec ns? I am having this issue that circular dependencies seem unavoidable

seancorfield 2020-04-22T01:12:19.237700Z

@ashnur The answer is "it depends". You should be able to find a partial ordering of dependencies that would allow you to split things into different namespaces -- probably three, so you have an "app" ns, a "spec" ns, and a "predicate" or "utility" ns that contains things the specs depend on, and the app can also depend on. But it may not be worth doing that analysis so having the specs in the same ns as your app code may just be easier.

seancorfield 2020-04-22T01:13:40.239200Z

If you're writing code that you want to be able to run on older versions of Clojure(Script) that don't include spec, you have to break them out into optional namespaces so that users can opt in if they want the specs -- but that's really only for library writers.

Aron 2020-04-22T01:14:28.240300Z

I am running shadow-cljs

seancorfield 2020-04-22T01:14:40.240700Z

At work, I try to have the data specs in a separate namespace (and do the work to untangle any problematic dependencies) but the function specs will generally go in the same namespace as the functions they are for.

Aron 2020-04-22T01:14:57.241100Z

I initially imagined having files for data/specs/components/react-app all separated

Aron 2020-04-22T01:15:46.241900Z

can I have multiple files all in the same namespace?

seancorfield 2020-04-22T01:21:30.243900Z

The simple answer to that question is no. The complex answer is there are ways to spread a namespace across multiple files but I don't think it will solve the problem you have here.

Aron 2020-04-22T01:22:05.244200Z

ok, no it is 🙂 I want to keep it simple

Aron 2020-04-22T01:22:47.245Z

I must be doing something silly again because I am unable to refer to my s/defs from the spec file/ns

seancorfield 2020-04-22T01:24:29.245700Z

Can you share some code to illustrate the problem? Is this in a project up on GitHub?

Aron 2020-04-22T01:29:51.245900Z

in spec file I wanted to do something like (s/def :my.specs/one-spec identity) then in app file ns require [my.specs :as myspecs]

Aron 2020-04-22T01:31:55.246100Z

it's closed source but I can make a new repo with completely new code, it might just take a couple of weeks before i have the time

Aron 2020-04-22T01:31:59.246300Z

😄 only half kidding though

seancorfield 2020-04-22T02:00:38.246700Z

OK. And what can't you do in the app file ns?

seancorfield 2020-04-22T02:01:08.246900Z

(sorry for the delay in responding -- was dealing with an issue someone just opened on clj-new that I needed to repro!)

seancorfield 2020-04-22T02:04:06.247100Z

In you app file ns, after that require, you should be able to reference that spec either as :my.specs/one-spec (i.e., its fully-qualified name) or ::myspecs/one-spec using the auto-resolve syntax which will expand ::myspecs to :my.specs using the alias of the namespace... the latter requires that the actual spec name really matches the spec ns in the qualifier. (and you could just (s/def ::one-spec identity) in the spec ns to have the spec automatically match the ns of the namespace it is defined in).

Aron 2020-04-22T02:04:23.247300Z

I feel bad if you apologize for such stuff, I realize people have lives beyond what is visible here : )

Aron 2020-04-22T02:04:41.247500Z

I had to do (def (s/def ... and it worked

Aron 2020-04-22T02:04:51.247700Z

for some reason I thought just (s/def would be enough

Aron 2020-04-22T02:05:34.247900Z

I am also in utter confusion about how keywords work, not just in spec but other places. I know it's a symbol that retuns itself, but apparently it also can hold specs

seancorfield 2020-04-22T02:06:47.248100Z

s/def updates a registry behind the scenes which is essentially a map from keywords to spec objects. The keywords don't "hold" specs -- the association is done separately.

Aron 2020-04-22T02:07:00.248300Z

gotcha

seancorfield 2020-04-22T02:08:37.248500Z

I have no idea what (def (s/def ...)) would do... but it's definitely not the right thing to do.

Aron 2020-04-22T02:10:23.248700Z

sorry, (def name-of-spec (s/def

seancorfield 2020-04-22T02:10:44.248900Z

That's what I assumed -- not the right thing to do.

Aron 2020-04-22T02:12:23.249100Z

so much black magic 😞

seancorfield 2020-04-22T02:12:28.249300Z

The "name-of-spec" is the keyword. That's how you refer to it in code that calls s/valid? or something.

Aron 2020-04-22T02:12:54.249500Z

so specs can only be registered to keywords?

seancorfield 2020-04-22T02:13:12.249700Z

Yes.

Aron 2020-04-22T02:13:48.249900Z

docs said resolvable symbol k

Aron 2020-04-22T02:13:57.250100Z

I am confused, that's all

seancorfield 2020-04-22T02:14:08.250300Z

Link? So I can see what the context is.

Aron 2020-04-22T02:14:27.250500Z

https://clojuredocs.org/clojure.spec.alpha/def

Aron 2020-04-22T02:15:45.250700Z

how can I use :require :refer to import a spec definition?

seancorfield 2020-04-22T02:16:06.250900Z

Ah, probably because of function specs: s/fdef uses the fully-qualified function name (symbol) so that's probably why s/def will accept a symbol.

seancorfield 2020-04-22T02:16:14.251100Z

You can't refer in a single spec.

seancorfield 2020-04-22T02:16:38.251300Z

Once you've loaded the ns in which specs are defined, they are globally available.

seancorfield 2020-04-22T02:16:49.251500Z

They're not like Vars or functions.

seancorfield 2020-04-22T02:17:26.251700Z

So you could require the specs ns in whatever you app entry point is and you would have access to those specs (as keywords) everywhere in your program.

Aron 2020-04-22T02:21:12.251900Z

I can't even require them at this point

Aron 2020-04-22T02:21:41.252100Z

how to "load the ns", I usually just do :refer or :as, neither which seems to work here

seancorfield 2020-04-22T02:22:21.252300Z

Just require the namespace like any other. Then the specs are in the registry and available globally.

Aron 2020-04-22T02:22:35.252500Z

oh ok, so i can just write the ns :as, but then i have to completely ignore it

Aron 2020-04-22T02:23:57.252700Z

and instead always have to read the file of the spec, because ns-publics don't list it

seancorfield 2020-04-22T02:24:16.252900Z

Yeah, if you're not using the :: auto-resolve syntax, you don't even need :as

Aron 2020-04-22T02:24:16.253100Z

and it's available via some (black, that is, unobservable) magic

seancorfield 2020-04-22T02:24:35.253300Z

(:require ... [my.specs] ...)

Aron 2020-04-22T02:24:41.253500Z

but how? just (:require [my.specs])?

Aron 2020-04-22T02:24:45.253700Z

ok 🙂

Aron 2020-04-22T02:24:51.253900Z

thanks again

Aron 2020-04-22T02:25:27.254100Z

when I think I understand something, it turns out that thing is specific to that particular area, and something else using the same syntax behaves completely differently

seancorfield 2020-04-22T02:25:42.254300Z

Here's where the docs talk about the registry https://clojure.org/guides/spec#_registry -- don't know if that'll help?

Aron 2020-04-22T02:27:55.254500Z

it will help 🙂

Aron 2020-04-22T02:28:39.254700Z

the problem, which you have to realize is a problem, that I've had this page open for days and I have read it through from top to bottom and bottom to up several times

seancorfield 2020-04-22T02:29:38.254900Z

Don't worry, sometimes it taking a lot of reading the Clojure docs before it actually makes sense and you get to see a big picture!

Aron 2020-04-22T02:30:09.255100Z

I see the big picture, I just don't see the details.

Aron 2020-04-22T02:30:35.255300Z

🙂 i've been trying to use clojure for 8 years at least

Aron 2020-04-22T02:31:16.255500Z

this time I will succeed because finaly I can do stuff like this, waking up at 1:30 am, then suffering for an hour before you come to help 🙂

Aron 2020-04-22T02:31:26.255800Z

oh and because I can use shadow-cljs

Aron 2020-04-22T02:31:38.256Z

so the tooling is solved more or less

seancorfield 2020-04-22T02:33:14.256200Z

I hear great things about shadow-cljs -- when (if) I ever go back to trying to do ClojureScript, that's the path I'll take.

lambdam 2020-04-22T13:58:23.261900Z

Hello everyone, I am defining some specs in a .cljc file, some only exist in a #?(:clj (do ...)) , others in a #?(:cljs (do ...)) I get an error on a keyword at parsing time:

2. Unhandled clojure.lang.ExceptionInfo
   failed compiling
   file:/.../foo.cljc
   {:file
    #object[<http://java.io|java.io>.File 0x5b1b23e7 "/.../foo.cljc"],
    :clojure.error/phase :compilation}
             compiler.cljc: 1717  cljs.compiler$compile_file$fn__3955/invoke

1. Caused by clojure.lang.ExceptionInfo
   /.../foo.cljc
   [line 52, col 41] Invalid keyword: ::const/env.
   {:type :reader-exception,
    :ex-kind :reader-error,
    :file
    "/.../foo.cljc",
    :line 52,
    :col 41} 
Here the ::const namespace is declared only for .clj parts of code (:require ... #?(:clj [... :as const])) When I split this .cljc into two files .clj and .cljs, there is no error. Would it be related to spec or is it a more general error? It is the first time that it happens. I really don't have any clue. Thanks

alexmiller 2020-04-22T14:04:14.262900Z

it's more general - ::const relies on having a clojure runtime namespace context to resolve it - I'm not sure what the exact problem is without more context but generally you'll want to avoid these in reader conditionals

alexmiller 2020-04-22T14:05:01.263300Z

you should be able to just use :foo/const or whatever instead

lambdam 2020-04-22T14:41:00.265500Z

Thanks @alexmiller it works. It's not as convenient as the shortcut version but it's still better than two .clj and cljs files. If you want more info, don't hesitate to ask for. I'll send in a private message.