Fork me on GitHub
#clojure-spec
<
2016-05-31
>
kgzm00:05:52

How would one use spec with records, when records use unqualified keywords and spec mandates the use of namespaced keywords?

arohner00:05:40

@kovasb: AFAIK, that doesn’t exist currently, but it should be possible to write from cribbing coll-of

cfleming01:05:36

@alexmiller: Ok thanks, I don’t fully understand the second option but I’ll investigate it.

potetm01:05:52

I guess the obvious followup (maybe for #C06E3HYPR?) is: Are there plans to support exceptions in specs?

seancorfield01:05:38

Given that the spec describe data structures, and function inputs/output — what would it mean to "support exceptions" in specs?

potetm01:05:49

Yeah that's fair.

potetm01:05:51

My first pass idea was just to "list the possible exceptions". But I'm totally open to the idea that that's just a bad idea.

potetm01:05:38

I haven't thought it through or anything. Just noticed that I was hitting problems during generative testing because I couldn't declare that, say, arithmetic overflow, was an okay exception.

cfleming02:05:12

It seems like something you might want to specify.

cfleming02:05:34

It’s a potential output from a function, more or less.

seancorfield02:05:52

I can see pros and cons. Certainly in (unit) tests it can be valuable to say "given these inputs, I expect the following exception"...

potetm02:05:24

cfleming: Yeah that was my thought as well.

seancorfield02:05:53

But is that a failure to conform to its spec? It depends on whether the spec is considered to be "valid for all inputs that are valid" (and therefore "undefined" for invalid inputs)...

seancorfield02:05:36

I just went through this exercise with java.jdbc because there are lots of ways to generate exceptions from those functions… but I’m not sure how to specify that...

seancorfield02:05:24

I’m not even sure if it makes sense to try to specify that? What if the DB is down, or the table you ask for doesn’t exist or there’s a syntax error in your SQL…? How would you codify that in clojure.spec?

seancorfield02:05:53

How could you even list all possible exceptions?

potetm02:05:20

Yeah it's possible that that would be overly restrictive.

seancorfield02:05:21

(each JDBC driver throws its own types — do you just say "could throw Exception"…?)

seancorfield02:05:42

It’s a hard problem, either way. clojure.spec definitely has gaps when you have stateful functions (generative testing on java.jdbc functions isn’t possible in general — most garbage input will produce an exception, even if it is in the right "form").

potetm02:05:58

I dunno, perhaps not since it's not exactly stopping you from doing anything at the end of the day.

cfleming02:05:10

@seancorfield: Yeah, spec is mostly not that useful for me either, for similar reasons.

mfikes02:05:50

So Sean and Nolen both seem to have created a my.lib.main-ns.spec namespace to hold specs. Wonder if that will become a de facto place to put them for libraries.

seancorfield02:05:51

I took that approach so that you didn’t have to load the spec ns — so you could use the code with Clojure < 1.9.0

seancorfield02:05:09

Although the build system shot me in the foot since it compiles all namespaces(!).

seancorfield02:05:55

Consequently, the build plain ol’ fails on Clojure < 1.9.0. Not sure how to approach that (make the entire namespace conditional? Ugh!).

mfikes02:05:07

Hmm… need a good solution to that problem. Every lib will face it.

potetm02:05:39

Spec actually does this for test.check.

potetm02:05:45

It's non-trivial.

cfleming02:05:50

I’m just cutting and pasting clojure.spec.* and using Clojure 1.7.

mfikes02:05:09

Yeah, the dynaload. Hmm

seancorfield02:05:16

@potetm: But you can’t have an optional namespace that uses spec and get it through the build system.

seancorfield02:05:32

I already deal with conditional loading in the java.jdbc tests.

seancorfield02:05:01

Locally, I can run lein test-all and pass tests on every Clojure version from 1.4 to 1.9 — and only on 1.9 does it use the spec.

seancorfield02:05:04

But the contrib build system tries to compile the namespaces in the project… So maybe there’s some Maven incantation I can use to exclude the namespace from compilation (or whatever Maven is trying to do with it).

potetm02:05:24

Right so this is all in the build tool. Yeah I got nuthin....

potetm02:05:02

Well except for this problem, that tool seems pretty slick 🙂 I've never seen anything like it before.

mfikes02:05:23

Maybe someone can make a hacked-up stub do-nothing compatibility lib in the clojure.spec and cljs.spec namespaces that consumers on 1.8 can use, just so things can be loaded. Ugh.

seancorfield02:05:25

@potetm: Have you looked at core.typed or Prismatic Schema at all?

potetm02:05:20

No I mean the version matrix. All the JDKs all the clojure versions. A really nice idea for open tooling. (I've always had control over JDK and clj versions.)

seancorfield02:05:32

Tomorrow I’ll talk to @alexmiller about the build system and see if we can figure out something ...

seancorfield02:05:13

Sean: 1, Maven: 0 😈 So it turns out a contrib project can override the parent pom.xml and suppress the Maven-initiated compile phase: https://github.com/clojure/java.jdbc/commit/b224a3e86df8c00a33a16122e6fcc531c5f71e2e

seancorfield02:05:34

Now I feel dirty for having to learn that much about Maven 😞

seancorfield02:05:24

Apparently if I want to get really "clever" I could probably create a conditional profile based on the Clojure version and have it still run compile if we’re using 1.9.0… Ugh! <profiles> ...

andrewhr12:05:58

@seancorfield: lein's {:aot :all} doesn't kick in for included dependencies, did it? Maybe that's the reason for mavencompile's strategy

akiel14:05:27

@anmonteiro You had an example of clojure.test integration were you used spec-is. I can’t find spec-is in the sources. I’m also interested in a proper clojure.test integration of clojure.spec.test/check-var. clojure.spec.test/run-tests only works in the REPL for me. I need it in leiningen.

anmonteiro14:05:54

@akiel: spec-is was something I wrote:

(defmacro spec-is [res]
  `(clojure.test/is (true? (:result ~res))))

akiel14:05:30

@anmonteiro: ok thanks this works.

akiel15:05:42

@anmonteiro: I’ve extended the is macro in the following gist. This looks even better to my eyes. https://gist.github.com/alexanderkiel/931387c7a86c1879b2267ad064067af7

seancorfield17:05:13

@andrewhr: The pom.xml file indicates the compile is just a "sanity check" so I’m taking that as "optional"...

ghadi19:05:55

Is there anything in between s/keys and s/map-of for heterogenous maps --- maps with keywords and structured values as keys?

seancorfield20:05:55

As I spec’d java.jdbc I found myself wanting a way to constrain the values of the optional keys in the optional opts argument. I suspect the only way is (s/and (s/keys …) #(some custom predicate)) ?

seancorfield20:05:27

(I’d have to take a look at what s/keys conforms values to)

kenny20:05:16

Are you guys tending to write your fdefs in a separate ns or in the same ns above/below where the function is written?

sekao20:05:35

i’ve been putting them above my functions so far

kenny20:05:44

Yeah that is great for readability but it seems like it kinda pollutes your ns.

zane21:05:56

How would one spec a map with non-keyword keys and heterogenous values (the specs of which are dependent on the keys)?

zane21:05:08

That is, how would you spec ::person from the guide if ::first-name ::last-name etc were strings?

zane22:05:08

Or, to put it another way, is there a version of clojure.spec/keys that works with non-keyword keys?

seancorfield22:05:40

@zane: I suspect you’d need to say (s/map-of string? ::s/any) and then have some custom predicate on the conformed value.

zane22:05:00

Right, okay.

zane22:05:11

As I'd feared.

seancorfield22:05:31

@kenny: I think overall I’d prefer data structure specs in a separate ns and fdef alongside the functions themselves but I won’t have a solid feel for that until we’ve used it a bit more heavily.

seancorfield22:05:58

In clojure.java.jdbc, I put all the specs in a separate ns so users on Clojure < 1.9.0 could still use the library.

kenny22:05:26

Makes sense.

zane22:05:46

@seancorfield: If I wanted to try to recover the the features of clojure.spec/keys but for maps with non-keyword keys would you recommend I implement clojure.spec/Spec myself?

seancorfield23:05:36

I suspect that will be a lot of work (but I haven’t looked at it). Since the push is for namespaced keywords — but unnamespaced keywords are also supported — I guess I would have to question your desire to define an API based on maps with non-keyword keys?

seancorfield23:05:58

By which I mean, what specifically is it that you’re trying to spec out here that isn’t a "regular" Clojure map?

seancorfield23:05:29

(and, perhaps therefore, spec "at large" is not designed for your use case?)

seancorfield23:05:39

My sense with clojure.spec is that it’s opinionated deliberately to encourage a particular style of API specification… "idiomatically Clojurey"… The comments in particular about namespaced keywords being "tragically underutilized" and that namespace-qualified keywords is "a practice we’d like to see grow"...