Fork me on GitHub
#clojure-spec
<
2017-02-03
>
joshjones02:02:06

@fnil, it's always been this way...

luxbock07:02:26

finally starting to get a hang of how to use instrument effectively while doing interactive development via the REPL, :replace is very handy in isolating parts of a long pipeline of functions that build up the computation step by step

luxbock07:02:58

having a version of enumerate-namespace that recursively enumerates all the internal functions called by some top-level function would be quite handy

luxbock07:02:41

not sure if that already exists in some library, if anyone knows let me know

villesv09:02:49

@ghadi @joshjones You are correct and I am embarrassed 😄 I think the case at hand may have contributed to the confusion. I was applying specs to a deep, previously unspec:ed map where both spec:ed and unspec:ed keys were present.

chrisblom09:02:58

i'm converting the json schema for AWS cloudformation to clojure.spec

chrisblom09:02:16

this schema has a few reflexive references

chrisblom09:02:46

i'm running into problems when converting it to spec

chrisblom09:02:51

i have a spec of form (s/def :foo/bar ...) where :foo/bar is used somewhere in the ...

chrisblom09:02:36

this gives me an Unable to resolve spec error, what's the recommended way to do such circular definitions in spec?

villesv10:02:28

Oh, I would love to have some sanity brought on to cloudformations json. Love the service but I stumble on the JSON details all the time

villesv11:02:48

How is :foo/bar used recursively? Doesn't something like:

(s/def :foo/bar (s/keys :opt [:foo/bar]))
(s/valid? :foo/bar {:foo/bar {:foo/bar {}}})
work? Or am I being naive?

frank14:02:35

that seems to work in the repl

joshjones14:02:09

@chrisblom What @fnil has suggested works for a map. A more fleshed out example:

(s/def ::k string?)
(s/def ::m (s/keys :req [::k] :opt [::m]))
(s/valid? ::m {::k "abc" ::z 42
               ::m {::k "def"
                    ::m {::k "ghi"}}})

joshjones14:02:18

but I don't know if you're spec-ing a map, a collection, or what ? you can also do recursive definitions for collections, etc., but if you can be more specific about the structure you're trying to spec..

chrisblom15:02:23

hmm thanks guys, it's working now, not sure what i was doing wrong

prepor15:02:03

Hello. I think that fully namespaced keywords without full application's namespace should be considered as very bad practice (:message/state for example) at least in library code. But why the official guide is full of such usages?

(s/def :event/type keyword?)
(s/def :event/timestamp int?)
(s/def :search/url string?)
(s/def :error/message string?)
(s/def :error/code int?)

villesv15:02:03

@prepor Why do you think so?

joost-diepenmaat16:02:56

I think I agree @prepor. since specs are global I would say that libraries should never use keys outside of the namespaces already in the lib

joost-diepenmaat16:02:11

to prevent clashes with application code and other libs

frank16:02:51

I think it makes it a tad harder to find the namespace where the s/def lives. Also, if you're referring to the specs in other namespaces, it's harder to figure out which namespace you need to require in order to have those specs available

prepor16:02:07

@fnil because of @joost-diepenmaat explanation, yes

villesv16:02:04

All true, although I find the flexibility great.

joost-diepenmaat16:02:09

I’m using single-keyword namespaces in an application right now and it’s very neat. Writing libraries generally means sacrificing some easyness for interoperability

villesv16:02:19

I definitely agree that it can be hard to locate where a certain keyword was defined (or sometimes redefined)

prepor16:02:47

@joost-diepenmaat a boundary between application and library is often not clear. today it's application code, and tomorrow you can decide to split it into libraries to use inside your microservices.

prepor16:02:55

so, personally I decided to not use "short namespaces" at all. and for me it's strange that official guide forces this usage. maybe I don't understand something...

seancorfield16:02:15

The guide uses ::stuff in most places tho` which is qualified by the full namespace. I think the other places in the guide are just examples -- certainly not "forcing" any particular usage on you.

joshjones16:02:09

The spec guide seems to be aimed at learning how spec works, and as such, brevity and simplicity are key -- adding too much info on namespaces makes it more difficult to learn. ::mykey is short, and simple ... at any rate, if you want to do something like this, I think it's a good way to shorten the code while still being namespace-safe:

(create-ns 'my.app.events)
(alias 'event 'my.app.events)
(s/def ::event/type keyword?)

prepor16:02:52

When something is used in guide without red warnings — it's "forcing" )

prepor16:02:31

@joshjones yes, I know about create-ns / alias

seancorfield16:02:51

It's a guide not a set of rules. You're reading too much into it.

seancorfield16:02:53

If anything I'd say the core team don't provide enough guidance. They really don't force their views on anyone.

prepor16:02:36

@seancorfield will you think the same when you catch a bug because two of your dependencies have name conflicts without any warnings because the official guide guided their authors to not always use fully qualified keywords? 🙂

prepor16:02:30

It's near the only way how you can broke others code in clojure ecosystem in non tricky way, I think

seancorfield16:02:44

When the core team talk about spec, they're pretty clear about using namespaces to prevent exactly that bug. Again, you're treating a learning guide as a rule book. There doesn't seem much point in this discussion if you're set on blaming the core team for your mistakes 😸

prepor17:02:22

hm. wrong tools force me to make my mistakes. is there no chance that core team did something wrong? don't think so. I'm sure that its ok, then somebody asks questions about core team decisions.

prepor17:02:03

I'm trying to find some big real world applications on github which uses core.spec but can't 🙂

sattvik17:02:15

One option I have found that can work is using the :full.ns.no.alias/kw form can help work around circular dependencies.

seancorfield18:02:30

@prepor We use spec in production fairly heavily — and I know there are other companies already doing so — but of course you won’t find commercial application code on GitHub 🙂

seancorfield18:02:30

@prepor And remember the saying: “It’s a poor craftsman that blames his tools.” (not sure whether that saying originates but I remember hearing it a lot growing up)

fenton18:02:24

can you spec a variadic function?

sattvik18:02:40

Sure. You use the regex specs to do so.

sattvik19:02:21

You can do something like:

(s/fdef hello
  :args (s/cat (s/? string?))
  :ret string?)

(defn hello
  ([] (hello “world”))
  ([name] (str “Hello, “ name \!)))

fenton19:02:15

ok... I haven't looked into this much but wondering about doing pattern matching with core.match and spec to be like a guard or something...

Alex Miller (Clojure team)19:02:06

@prepor the guide uses shorter names and :: kws for readability. it would be reasonable to add a side bar explaining this.

prepor19:02:23

@alexmiller cool, thank you! the only thing which I imagine to catch (and debug) such errors automatically is "production mode" for clojure.spec which forbids redefinition of specs in explicit way

spieden19:02:35

@fnil we generate cloudformation templates as EDN and serialize to JSON, works great

spieden20:02:08

@chrisblom that sounds like a great project. huge surface area, though

villesv20:02:59

@spieden very cool! I have had such a thought but have not fully grasped cloudformation and its template language yet

spieden20:02:37

it’s a bit of a curve but has been a great workhorse for us

spieden20:02:51

can’t imagine maintaining a template by hand, though

spieden20:02:06

we have lots of functions that build up common structures, etc.

spieden20:02:45

without DRYing things out like this it’d be crazy town

villesv20:02:59

Spec should be great for it

spieden20:02:12

yeah for sure. they have their own (hosted) validation operation, but it misses things and works against the JSON representation

villesv20:02:46

So I noticed 😄

kassapo22:02:52

Could you help a Newbie: I am going through http://blog.cognitect.com/blog/2016/10/5/interactive-development-with-clojurespec and cannot get past

codebreaker=> (s/exercise (:args (s/get-spec `score)))

FileNotFoundException Could not locate clojure/test/check/generators__init.class or clojure/test/check/generators.clj on classpath.  clojure.lang.RT.load (RT.java:458) 
I am using Clojure 1.9.0-alpha14 in lein repl

jr22:02:41

add [org.clojure/test.check "0.9.0"] to your (dev) dependencies