Fork me on GitHub
#clojure-spec
<
2018-10-21
>
borkdude21:10:49

@gfredericks yikes, in RC1 as well. maybe a bug? EDIT: it was valid in 1.8.0 as well

borkdude21:10:31

it’s probably not meant as a public function anyway?

gfredericks21:10:52

I hadn't considered that; I'm not sure

Alex Miller (Clojure team)22:10:31

That’s the compiler hook under fn

Alex Miller (Clojure team)22:10:38

Certainly not the preferred entry point

borkdude22:10:09

We’re writing some specs for clojure.core functions. I notice things can get a bit slower on big codebases with instrumenting all core functions. Is there a way to let spec know to not check when a function is called from clojure itself? so only external calls. I hoped direct linking would solve this, but I don’t think it is now

Alex Miller (Clojure team)23:10:27

I would not expect calls between core functions to get checked

andy.fingerhut23:10:12

I would be very surprised, if you are compiling Clojure with the default option of direct linking enabled, that calls between Clojure functions within Clojure are being checked, if you are using instrument. If you believe you are seeing otherwise, I would love to see an example of that.

andy.fingerhut23:10:33

instrument works by re-def'ing Vars. direct linking means that the current value of the Var is ignored, instead being embedded in the calling function at compile time.

andy.fingerhut23:10:35

FYI, there is one function in clojure.data/diff's call tree that calls a function in clojure.set (I think clojure.set/difference) with non-set arguments. I have tried writing a spec for clojure.set/difference that causes errors if you call it with anything other than a set, and the only way I could make the error be caught is to disable direct linking when compiling Clojure.

andy.fingerhut23:10:01

And if you want to try compiling Clojure with direct linking disabled, and thus likely see instrumented runs get even slower, there are some instructions near the bottom of this page, with the heading "Building Clojure without direct linking": https://dev.clojure.org/display/community/Developing+Patches

borkdude06:10:10

Thanks. Then my understanding of direct linking is correct and I need to do more research to see how to speed up things.

hmaurer23:10:27

is there a shortcut for a Spec s/or which only contain spec keywords and want to tag them with the same keyword? i.e. (s/or ::foo ::foo ::bar ::bar ...)

hmaurer23:10:49

Thanks @alexmiller. Other question: I read that specs are discouraged to be used as runtime because they can be slow. With that in mind, would it still make sense to use specs at runtime to branch on code based on the shape of data. i.e. check if data conforms to some spec to know if it’s of some “kind”, branch on that, etc

hmaurer23:10:03

use it as duck typing for dynamic dispatch

hmaurer23:10:16

i.e. use s/valid? and s/conform pretty extensively in runtime code

Alex Miller (Clojure team)23:10:24

Only you can answer whether it’s fast enough for you

hmaurer23:10:58

It’s definitely fast enough for me; I’m just wondering if it goes against some deeper philosophy that I’m missing and could come bite me in the back down the line (beyond performance)

hmaurer23:10:53

I’ve another question on Clojure spec for whomever is around: how do you avoid circular namespace dependencies? It seems preferable to put every spec in a namespace mapping to the namespace part of the spec keyword to be able to then require and alias that namespace wherever the spec is used. i.e.

(ns my-app.schema
  (:require [my-app.schema.person :as person]))

(s/def ::person (s/keys :req [::person/first-name]))
(ns my-app.schema.person)

(s/def ::first-name string?)
The simplest example of the issue I’m running into is, then, what if I want to add a friends attribute on a person. i.e.
(ns my-app.schema.person
  (:require [my-app.schema :as schema])) ; oops, circular dependency!

(s/def ::first-name string?)
(s/def ::friends (s/coll-of ::schema/person))

hmaurer23:10:05

The only solution I can think of it to still create the my-app.schema.person namespace but to move the attribute specs for person in the my-app.schema namespace, like this:

(ns my-app.schema)

(s/def :my-app.schema.person (s/keys :req [:my-app.schema.person/first-name :my-app.schema.person/friends]))

(s/def :my-app.schema.person/first-name string?)
(s/def :my-app.schema.person/friends (s/coll-of :my-app.schema/person))

hmaurer23:10:00

actually I could still use the namespace alias here, but I would have to define the attribute specs in my-app.schema namespace and essentially just create an almost blank file for the my-app.schema.person namespace

misha23:10:31

> It seems preferable to put every spec in a namespace mapping to the namespace part of the spec keyword false opieop actually, "it really depends..."

misha23:10:46

imagine random map flowing through your app code. Do you really want to look for :my-app.schema.person/first-name in it? or is something more readable would be better and enough? (and I bet :my-app is much longer, and you'll end up with keys violating PEP8's 80 chars length in no time)