This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2018-11-20
Channels
- # announcements (2)
- # architecture (5)
- # beginners (118)
- # cider (5)
- # clara (13)
- # cljdoc (8)
- # cljs-dev (49)
- # cljsjs (2)
- # clojure (107)
- # clojure-dev (9)
- # clojure-europe (3)
- # clojure-italy (58)
- # clojure-japan (2)
- # clojure-nl (6)
- # clojure-spec (89)
- # clojure-uk (27)
- # clojurescript (9)
- # core-async (33)
- # cursive (2)
- # datascript (2)
- # datomic (31)
- # duct (4)
- # emacs (1)
- # events (1)
- # figwheel-main (1)
- # fulcro (69)
- # hoplon (7)
- # hyperfiddle (16)
- # incanter (4)
- # instaparse (4)
- # kaocha (1)
- # mount (2)
- # nrepl (19)
- # off-topic (40)
- # onyx (6)
- # other-languages (3)
- # pedestal (2)
- # re-frame (48)
- # reagent (2)
- # reitit (10)
- # ring-swagger (9)
- # shadow-cljs (63)
- # spacemacs (13)
- # sql (8)
(without unioning the value of the key under something like s/keys :req [:a/foo]
where s/def :a/foo (s/or :b :a/bar :baz :a/baz)
(since i want the key’s value to be either :bar
or :bar
and not :foo
)
Is there any difference between: (s/& (s/cat ....
and (s/and (s/cat ...
& is a regex op that nests with other regex ops
I read some spec impl code, I see it using a global store for these specs. I think spec is more of meta data of data, why it cannot implemented via meta data? Make it a meta system?
metadata of what?
When I define a spec for a keyword, where exactly would you attach the metadata?
@xfcjscn909 https://clojure.org/about/spec#_don_t_further_add_to_overload_the_reified_namespaces_of_clojure
@roklenarcic s/&
is for spec regexes while s/and
is for general predicates
Well, specs are not tied to a var, so meta wouldn't really make sense. They are tied to values. The keyword or symbol is just a name for the spec
That's why check-fn
takes a function and a spec seperate. Because you could use any fspec to spec to check any function
Ya, I mean, in practice, for functions, its convenient to use the same symbol to point to your function and its spec.
@schmee i am in china, now i cannot open that url, i will check that article later, thanks for the information.
i think spec is meta data in essence, whatever it currently implemented via meta mechanical or not.
i think the problem is keyword should support meta data as we are associating meta data to it.
Keywords are interned and reused so cant support metadata
i think now it’s a workaround to impl meta data in global store, is is really a good practice to do so?
It depends what the meta is about. Like if you want to specify additional things about a Var then you can add that to the Var meta. Same for anything that supports meta.
And values can not have meta attached to them directly. A value can be an int for example
So say you want to give that spec a name, you can do s/def ::greater-then-ten #(> % 10)
You did not add meta to the keyword ::greater-then-ten here. This spec is not metadata about the keyword.
So I'm not sure you should think of Specs as meta data. It isn't really meta data in the normal sense. Like, yes, in this case, you can say that 15 conforms to the ::greater-then-ten spec. And so, ::greater-then-ten can be seen as metadata about the value 15. But again, meta about values is not really a concrete thing.
in my opinion there are plenty of problems about current spec impl, for example: global store for spec, use keyword as spec name, mix keyword with spec, instrument is a state changer...
vars are "global", shoving everything in them would be the same ultimately, you just move the bloat somewhere else. A separate registry is a good thing
ask youself: where is the info about the Types "stored" (if that even makes sense) in haskell: it's not a first class thing
spec-alpha2 is supposed to fix quite a bit of the common complains, so I guess "wait and see"
• The global store has advantages too. It is simpler to manage a single global store, and namespaces should avoid clashes. • You don't have to use keywords for spec names, you can also use symbols. But I think keywords was chosen as convention specifically to make it visually separate from Vars
* Instrument is used for testing only. And, it shouldn't be altering state. Think of it as aspect oriented programming if you know about that.
instrument directly changed the function via byte code operate, i hope instrument can return a new function not directly change on existing function
instrument doesn’t change the original function, it wraps it in a new function that’s stored in the root of the var
an alternative could maybe have been via metadata on the var: instrumented? true
but that would incur performance overhead when not using spec, because when calling a function via a var you would have to do this check
But it does mean you can not have an instrumented fn in one thread, and an uninstrumented one in another. Though that almost sounds like a positive in this case.
Oh, that's true, I just saw the instrumented code checks for a dynamic var to decide to validate or not. So I guess you could in fact do that.
Hum, that gives me an idea for when I alter-var-root things in my tests. I could instrument things to be "mockable", and then have a dynamic binding pointing to a mock, and this different mocks per thread and my tests would work in parallel.
@xfcjscn909 If you wanted non global stores, you'd have to first create a spec registry and put it somewhere in scope. And if it wasn't in scope anymore, it would stop working. And then as soon as you have more than one, you might forget which registry holds the spec you are looking for. All spec functions would take an additional arg for the registry to use. I mean, it would not be terrible, but I feel it would be a bit more inconvenient. And in practice, I never felt the need for separate registry. That's what namesapces are for on symbols and keywords.
In effect, you would be using a Var as a namespace mechanism, instead of just using the existing namespace mechanism of keyword and symbols I feel.
Clojure apps pretty much converged to “one global atom” instead of “many smaller atoms”, e.g. re-frame
Also I'd say, if you don't find that top level defs are a problem for defining Vars, in practice, Specs are defined in a similar fashion, so it'll be a similar experience.
the thing that would maybe problematic is if multiple libraries define specs for the same thing. e.g. lib1 defines a spec for clojure.core/merge
and lib2 does too. currently you have no way to say: I want to exclude loading this fdef
when requiring a namespace
Hum, right. I think I tend to use Spec much more around my data, and a lot less to spec functions. So I haven't faced these kind of issues very much.
it hasn’t been a major problem, but it would be useful to me to see from which namespace a spec comes from and to conditionally instrument depending on the namespace where it came from.
e.g. here I have some code only instrument/unstrument specs from speculative: https://github.com/slipset/speculative/blob/master/src/speculative/instrument.cljc but if the “where did my spec come from” feature existed, I didn’t have to
but maybe in a future version of spec specs will have some form of metadata, so it could also happen there
Is there a way to define a spec that matches the structure of a conformed value?
E.g. (s/cat :a string? :b string?)
would conform to {:a "a" :b "b"}
. Now I want to instrument a function so that it only takes values having :a
and :b
with values matching string?
automatically, no
ok cool, thanks. Is the general expectation that once values are conformed they are no longer passed to functions that have spec'ed arguments? (I guess in most cases conformed values won't match the original spec)
Is there a way to make a spec to check if a vector has either 1 or 2 values, where the first value is a keyword and the second value is "anything or nothing"?
I was thinking this would work, but it does not: (s/def ::event (s/tuple keyword? (s/nilable any?)))
tuples are fixed size
the regex ops cat, alt, +, *, ?, etc are regex ops used to describe the structure of a sequential collection