Fork me on GitHub
#clojure-spec
<
2020-11-13
>
borkdude16:11:20

What is the reason spec chose a custom deftype LazyVar over the built-in delay in its implementation?

borkdude16:11:32

I'm trying to come up with something that would work in Clojure for this case:

(def input (LazyVar. (fn [] (line-seq (java.io.BufferedReader. (java.io.StringReader. "1\n2\n3\n")))) nil))
such that you don't have to write @input but just input so the first time it's derefed by Clojure it starts its realization. Just a naked line-seq doesn't work, since that starts reading once it's def-ed.

borkdude16:11:41

@alexmiller in the gen namespace

borkdude16:11:06

I think in Clojure I would have to write a subclass of clojure.lang.Var to make that work.

Alex Miller (Clojure team)16:11:33

sorry, I don't actually see what you're talking about

borkdude16:11:35

And maybe I should just go with @input and not do any magic... This lead to the question: why is gen/LazyVar not just a delay but a custom data structure. Ah right.. sorry, the LazyVar is something in CLJS, not CLJ. facepalm

borkdude16:11:38

I'll ask over there in #clojurescript

socksy18:11:26

I am confused about the syntax for (or) and (and) in s/keys. My understanding of it was that anything that is passed to or could be correct, and anything that passed into and has to be present. Did I misunderstand? My intuition does not work for the following example:

(s/def :foo/foo #{:foo})
(s/def :bar/foo #{:bar})
(s/def ::an-int int?)

(s/def ::baz (s/keys :req-un [(or :foo/foo
                                  (and :bar/foo
                                       ::an-int))]))

(s/valid? ::baz {:foo :foo})
;; => false
(s/valid? ::baz {:foo :bar})
;; => true

socksy18:11:51

ok it looks like when you have the same naked keyword (not sure of the right terminology, keyword without the NS) then it will always take the last one defined. That's a huge bummer, since I wanted to be able to spec something like "In this case, do this, in this other case, do this + another piece of data", and the way that was being specced before was by storing everything as a tuple

borkdude18:11:38

@socksy can't you use s/or for either case?

borkdude18:11:52

more verbose

seancorfield18:11:12

@socksy You'll need to wrap s/keys with s/and and add your rules via a predicate -- or use s/or around s/keys as @borkdude suggests.

socksy18:11:22

yes I think it might be possible. I'll go hit my head on it

socksy18:11:36

i am thinking my own predicate will probably be the most readable but let's see

borkdude18:11:11

maybe spec2 has a better answer to this... although I'm not sure if s/select can solve this case

seancorfield18:11:45

Another option would be a multi-spec I think?

socksy18:11:34

(s/def ::baz (s/or :foo-case (s/keys :req-un [:foo/foo])
                   :bar-case (s/keys :req-un [:bar/foo ::an-int])))
is not too bad actually

👍 3
borkdude18:11:05

Now I wonder how you would use this in spec2. I think you would define ::baz as the thing with all possible keys and then use s/select for either case?

borkdude19:11:33

(s/def ::baz (s/schema [:foo/foo :bar/foo ::an-int]))
(s/def ::foo-case (s/select [:foo/foo]))
(s/def ::boo-case (s/select [:bar/foo ::an-int]))
Something like this?

🤷 3