Fork me on GitHub
#clojure-spec
<
2016-06-24
>
bsima02:06:56

How do you spec protocol functions? Is it the same as spec-ing a regular function? (I haven't actually tried it yet...)

bsima02:06:42

I tried to spec a multimethod using fdef a few days ago and it didn't work but I didn't have time to figure out why

seancorfield02:06:33

@bsima: Read this issue for some information about spec and protocols http://dev.clojure.org/jira/browse/CLJ-1941 (regarding instrumentation)

bsima02:06:25

mm thanks seancorfield

jannis15:06:37

How do I best write a generator for :args? It seems like even if I use (gen/cat <sequence-generating generators>) it generates a sequence that is then passed to :args as the first argument, instead of "splicing" it into the macro/function call.

akiel15:06:37

@jannis Is it not sufficient for you to write individual generators? Do you have many dependencies between your args?

jannis15:06:21

The args are fairly flexible and somehow what gets generated for name and & forms is not quite what it should be. Perhaps my :args spec is wrong (thinking var args perhaps need special treatment)?

jannis15:06:21

Even if I just use (s/cat :name ::command-name) and drop the & forms argument in the macro, check-var complains with "Wrong number of args (1) passed to: command/defcommand". Something there is odd.

akiel15:06:41

Yes (s/cat :name ::command-name) generates only one argument

akiel15:06:22

varagrs is no special - you have already a s/* in your args

akiel15:06:42

what is ::command-name?

jannis15:06:47

But one argument should be fine for a macro that takes exactly one argument.

jannis15:06:17

It's a symbol? spec

akiel15:06:59

ah yes you are right - one arg should be possible

jannis15:06:05

I can paste the entire file once my laptop has rebooted.

akiel15:06:18

I get the same wrong number of args message with check-var

akiel15:06:37

but if I convert the macro into a function, it works

akiel15:06:52

ther may be some issues using char-var with macros

akiel15:06:02

I never spec’ed macros before

jannis15:06:11

Yep, I never ran into this with specs for functions.

jannis15:06:00

Actually, this is a Clojure + ClojureScript macro, which will just pass on the arguments to a function that does the actual work. I could move the spec to that function instead.

jannis15:06:14

That could work around the problem.

akiel15:06:21

but speccing macros is an interesting feature on its own - but check-var might simply not work with it

akiel15:06:50

I simply don’t know. I’ll hit this if a spec my first macro. But I have currently none.

jannis15:06:40

Moving the spec to the function and turning the var-args into a (s/cat :name ... :forms (s/spec (s/cat :description ...))) subspec structure does the job 🙂

jannis15:06:46

All the generated inputs are now useful.

akiel15:06:40

nice 🙂

kendall.buchanan16:06:28

Question about the direction of namespaced keywords:

kendall.buchanan16:06:12

With Clojurescript (Om appears to be pushing namespaced keywords) on the front end, specs in the middle, and Datomic on the end, namespaced keywords feel natural.

kendall.buchanan16:06:35

But if you’re working with a Javascript front-end, that doesn’t support them. And a SQL database on the other. What’s one to do in the middle if you want to leverage specs?

kendall.buchanan16:06:49

Just :req-un everything?

kendall.buchanan16:06:09

Or create translation layers across the board?

akiel16:06:49

:req-un works fine - the only thing you loose is automatic validation of all keys even if not present in req or opt

kendall.buchanan16:06:38

Makes sense. I’ve hesitated on spec for fear that they can’t live in “the real world” (a non-full-Clojure stack environment).

akiel16:06:46

even in clojure itself - nobody can change existing apis - so un-namespaced keywords will be still there

kendall.buchanan16:06:41

K, thanks @akiel.

seancorfield17:06:16

@kendall.buchanan: I’m working on making namespaced keyword support in java.jdbc a lot easier. In the upcoming 0.6.2 release you’ll be able to specify a :qualifier "foo" option on calls to get :foo/col-name back from all queries. I need to figure out the final story for what happens if you push :foo/col-name into java.jdbc.

kendall.buchanan17:06:31

@seancorfield: That’s very cool. I suspect work will need to be done on all ends of the stack to make namespaced keys more tenable for the average project.

seancorfield17:06:36

Now I look at it, I probably won’t need to do anything for pushing namespaced columns into java.jdbc:

user=> (def db-spec {:dbname "mydb" :dbtype "mysql" :user "tester" :password "secret"})
#’user/db-spec
user=> (j/query db-spec ["select * from status"])
({:id 1, :name "approved"} {:id 2, :name "new"} {:id 3, :name "rejected"})
user=> (j/query db-spec ["select * from status"] {:qualifier "status"})
({:status/id 1, :status/name "approved"} {:status/id 2, :status/name "new"} {:status/id 3, :status/name "rejected"})
user=> (j/insert! db-spec :status {:status/name "test"})
({:generated_key 13})
user=> (j/query db-spec ["select * from status"] {:qualifier "status"})
({:status/id 1, :status/name "approved"} {:status/id 2, :status/name "new"} {:status/id 3, :status/name "rejected"} {:status/id 13, :status/name "test"})

seancorfield17:06:15

And due to a very recent change, even this works as expected:

user=> (j/insert! db-spec :status {:status/name "qualifier"} {:qualifier "result"})
({:result/generated_key 14})

alexmiller18:06:23

@jannis: check-var (very soon to be just “test” in the next alpha) is not going to work with macros

alexmiller18:06:42

@kendall.buchanan: we are considering adding something in s/keys that lets you alias unaliased keys to arbitrary specs, but no guarantees

jannis18:06:23

@alexmiller: Will there be an equivalent for fdef'ed macros?

alexmiller18:06:34

you can fdef macros now

alexmiller18:06:18

it’s just that check-var is not going to work to test them, afaik

akiel18:06:56

Is there a way to compose multiple s/key specs into one big one so that a map has to satisfy them all?

bfabry18:06:38

@akiel: I wrote a macro that did that because I couldn't find anything. it was kinda painful

akiel18:06:06

@bfabry: I need it to work with multi-spec because I have a big environment map were I have multiple subsets of varing keysets.

bfabry18:06:20

I don't know enough about multi-spec to know if it would help, but here it is (very ugly) https://clojurians.slack.com/archives/clojure-spec/p1466110303000387

akiel18:06:41

Ah s/form is nice. Never used it.

akiel18:06:05

@bfabry: Thanks but your macro will only work with static s/keys specs.

bfabry18:06:23

yup, I couldn't find a way around that because s/keys is a macro

alexmiller18:06:12

@akiel you can just do s/and of multiple s/keys

bfabry18:06:40

@alexmiller: that won't create good generators though

akiel18:06:02

@alexmiller: Ok I only have to wrap all subsequent s/keys into a one-arg function and ignore the conforming value?

akiel18:06:23

@alexmiller: ok it works

alexmiller18:06:24

s/and will create a spec, not sure why you need to make it into a function

akiel18:06:46

No my reading of the doc was just to loose.

alexmiller18:06:50

the resulting conformed value should be the map

akiel18:06:32

I thought there would be always a predicate which gets the previous value. Bit this counts only for preds and not for specs.

alexmiller18:06:34

not sure I understood that

akiel18:06:46

The example is (s/and even? #(< % 42)) and the doc says: “Successive conformed values propagate through rest of predicates.” So I thought you can have one initial spec and than only predicates which are called with the previous conformed value.

bfabry18:06:50

@alexmiller: out of interest is there any move to make some of these macros functions? a dynamic s/keys seems like it could be useful

alexmiller18:06:53

@akiel: yes, although I think maybe you’re reading too much into the choice of “spec” and “predicate” there

alexmiller18:06:40

and combines specs which can be either predicates or other things

alexmiller18:06:47

the conformed value flows through them

akiel18:06:38

@alexmiller Ah ok. I see. The specs get also the previous conformed value and just use it to be able to return the whole thing at the end.

alexmiller18:06:50

@bfabry: yes, that’s possible. things are macros so that we capture forms for reporting purposes. but there may still be function forms as well (which would fill in under the macro forms)

fenton19:06:46

I have a multi-spec. My in data can look like: {:method :search :search-term "blah" :auth "abc123" :gps-lat 3.4 :gps-long 5.3} or {:method :get-products :product-id 12345 :auth "abc123" :gps-lat 3.4 :gps-long 5.3}. My multi-spec already keys off the :method key. My data has some shared keys: :auth, :gps-lat, :gps-long and some keys that are not shared: :search-term and :product-id. Ideally I'd like to create a spec that merges two s/keys specs into a single s/keys spec, however s/cat creates a spec that expects two hashes in a list as opposed to a single hash with merged keys.

alexmiller19:06:24

I talked through some options for something like this with @luke - maybe he could elaborate on where he ended up

alexmiller19:06:32

iirc, he ended up with a spec for the common keys and separate specs for each variant

alexmiller19:06:57

and then specs for each variant that anded common and separate

alexmiller19:06:54

and then instead of multi-spec, it’s an s/or of the concrete variants

alexmiller19:06:05

with the downside that it’s a closed system

alexmiller19:06:46

with multi-spec, you’d have to repeat the keys in each variant

fenton19:06:40

@alexmiller: okay, i'll look into what it looks like with s/or option and compare that to repeating in a multi-spec scenario. Thanks.

fenton19:06:46

the closed system you mention doesn't use s/keys?

alexmiller19:06:31

common = (s/keys …) A = (s/and common (s/keys A…)) B = (s/and common (s/keys B…)) all = (s/or :a A :b B)

alexmiller19:06:05

that doesn’t help you with the conforming question though

fenton19:06:23

@alexmiller: k i'll give that a try.

leongrapenthin23:06:44

@fenton @alexmiller I ran into this too, it seems a common scenario with Datomic "polymorphism" aka {:payment/amount 42, :payment/type :payment.type/stripe, :payment.stripe/payment-id 1234} - it would be great to have a merge-keys operation that takes two s/keys and merges their implementations - what do you think?

alexmiller23:06:33

Talked about it with Rich today