This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-04-09
Channels
- # announcements (1)
- # architecture (20)
- # aws (22)
- # babashka (41)
- # beginners (191)
- # chlorine-clover (66)
- # cider (19)
- # clj-kondo (54)
- # cljs-dev (15)
- # cljsrn (78)
- # clojars (1)
- # clojure (148)
- # clojure-android (4)
- # clojure-europe (7)
- # clojure-gamedev (15)
- # clojure-germany (6)
- # clojure-losangeles (46)
- # clojure-nl (23)
- # clojure-survey (3)
- # clojure-uk (46)
- # clojurescript (24)
- # conjure (21)
- # cursive (21)
- # data-science (11)
- # datomic (5)
- # events (2)
- # fulcro (28)
- # garden (32)
- # joker (2)
- # kaocha (6)
- # lambdaisland (4)
- # mount (2)
- # off-topic (11)
- # pathom (10)
- # pedestal (13)
- # re-frame (7)
- # shadow-cljs (15)
- # spacemacs (21)
- # specmonstah (1)
- # wasm (1)
- # windows (1)
- # xtdb (37)
So maybe this is a naïve question, but… Say I’ve registered a spec for my fn:
(s/fdef import-post!
:args (s/cat :remote-post post-spec/remote-post)
:ret post-spec/intern-post)
Is there any way to use the definition here of the spec for :args
within import-post!
to validate my input?Or can this spec only be used to validate the whole contract, with both input and output?
you can do this within :pre - there are examples of this in the clojure spec guide
@jings.bill instrument
only checks :args
-- you're aware of that?
I've recently found a library called https://github.com/jeaye/orchestra
> By default, clojure.spec will only instrument `:args`. This leaves out `:ret` and `:fn` from automatic validation; Orchestra checks all of them for you.
Which seems to work - :ret
parts are validated in my tests now.
I'm wondering why clojure.spec doesn't have this. There must some good reason which I'm not aware of yet 🙂
Is using orchestra
considered more like an antipattern?
Conceptually, instrument
is about checking calls -- that your code is passing the correct :args
-- whereas check
is about checking behavior, using generative testing: it generates random args per :args
, calls the function, and then verifies that :fn
and :ret
hold true. So it's two separate types of checking. @U0113AVHL2W
I see Andy gave you a good, long answer in another thread and linked to both the Spec FAQ and to Rich's conversation on the topic! I should have caught up with the main channel first I guess 🙂
check
is what exercises :ret
(and :fn
).
I am not aware of that
be aware that if you instrument your function, and one of your args is specced as a function, random data will be generated and passed to that function so don't do this with side effecting function args
Also "validate" is a bit imprecise: to me, that means a production run-time validation of data and appropriate error handling on failure 🙂
The spec guide shows :pre
, but: (1) doesn’t illustrate referring to :args
within the fdef
, and (2) I asked about that and apparently it’s not a recommended practice?
https://corfield.org/blog/2019/09/13/using-spec/ talks about various ways to use Spec in dev/test/production code.
Yeah, that’s what I’m referring to, Sean. I’ve got a function that currently falls down on bad input, and I’d like a clear failure
IMHO that's what :pre is for
don't instrument in prod
:pre
and instrument
are for dev/test really, not production -- for a lot of people -- because they're about assertions
fdef is for instrumenting as I understand it
Yeah, instrument seemed like the wrong tool
Yup. If you want this in production use s/valid?
or s/conform
and have an explicit handler for invalid data.
I’ve written this:
(defn import-post!
[remote-post]
(if (not (s/valid? (s/cat :remote-post post-spec/remote-post) [remote-post]))
(s/explain (s/cat :remote-post post-spec/remote-post) [remote-post])
...
…setting aside the obvious repetition, the spec (s/cat :remote-post post-spec/remote-post)
is precisely what I’ve written in :args
in my fspec
In theory, it would go: You've run st/check
on all your functions, you've instrumented your code in devo while doing manual testing and when running your unit and integ tests. So you know everything works. But, there are some things that depend on runtime input, like input from a user, an API, a file, the DB, etc. Since there's no way to know whatever gives you this input won't give you garbage, for that, you add an explicit s/valid?
or s/conform
.
or s/assert
That looks good to me, though you'd probably want to s/def
that spec so you're not repeating it like you said
I don't like s/assert
as much, because the rules around how to enable/disable it confuse me too much 😛
Also generally I like to control in prod the error returned or thrown with more granularity, but yea, it is also an option\
How would I use s/def
here? I thought it was used to wire namespaced keys to data specs?
You want:
(defn import-post!
[remote-post]
(if (not (s/valid? :post-spec/remote-post remote-post))
(s/explain :post-spec/remote-post remote-post)
...
is there any particular reason this isn’t a crazy idea:
(defn valid-against-spec? [spec args]
(if-not (s/valid? spec args)
(s/explain spec args)
true))
(let [args-spec (s/cat :remote-post post-spec/remote-post)]
(defn import-post!
[remote-post]
(when (valid-against-spec? args-spec [remote-post])
...))
(s/fdef import-post!
:args args-spec
:ret post-spec/intern-post))
apart from being kind of ugly and poorly named
Hum..., I think s/fdef is a macro no? Can it capture the value of the let like that I'm not sure
What's your hesitation for doing:
(defn valid-against-spec? [spec args]
(if-not (s/valid? spec args)
(s/explain spec args)
true))
(defn import-post!
[remote-post]
(when (valid-against-spec? :post-spec/intern-post remote-post)
...))
(s/fdef import-post!
:args (s/cat :remote-post :post-spec/intern-post)
:ret post-spec/intern-post))
that when is always true
oh it's a println error log, never mind
If you really wanted to reuse the args spec of fdef, there's a way to get it from the fdef I think. Can't remember on top of my head though
But still, to me those are different. You're trying to validate remote-post, and you already have a spec for it. The s/cat
is not the spec of remote-post, it's the spec of the argument vector of the function, that's why you need to do the shenenigan of converting remote-post
into a vector before you validate it against the arg vector spec. So I just feel it's a roundabout way.
If you s/get-spec the var symbol, that’s an fspec that supports keyword lookup of :args, :ret, :fn
(s/explain (s/cat :remote-post :post-spec/intern-post) [remote-post])
doesn’t yield as nice an error message as (s/explain :post-spec/intern-post remote-post)
.
b/c it’s not really validating the same thing: the former is validating the arg list, the latter is validating an individual argument by hand
i’ll try that, alexmiller. i didn’t think to just (:args (s/get-spec 'symbol))
the docs for what fdef
registers and get-spec
yields are opaque
I've recently found a library called https://github.com/jeaye/orchestra
> By default, clojure.spec will only instrument `:args`. This leaves out `:ret` and `:fn` from automatic validation; Orchestra checks all of them for you.
Which seems to work - :ret
parts are validated in my tests now.
I'm wondering why clojure.spec doesn't have this. There must some good reason which I'm not aware of yet 🙂
Is using orchestra
considered more like an antipattern?
There question is probably in an FAQ about spec somewhere -- it is definitely frequently asked.
One of the reasons orchestra exists is because many people want return value spec checking on many functions during testing, despite spec not helping you do that, except when running tests specifically on that function
Not sure I understand.
From what I see I can just use orchestra.spec.test/instrument
and it checks all specs, no need to call instrument on every function.
If you do not use orchestra, only the instrument that comes with Clojure.spec, no ret value checking is performed. orchestra does do ret value checking
You asked why clojure.spec doesn't have this -- this is asked so often, I am sure someone has written an answer to "why?' somewhere, but not sure where at the moment
Found it on https://blog.taylorwood.io/2018/10/15/clojure-spec-faq.html "Q: Why doesn’t `instrument` check my function return value?"
That is a guessed reason by the author of that article, who did not write spec, nor apparently did they ask the author of spec
Here is an older answer to the question, plus a link to where Rich Hickey answered it: https://groups.google.com/forum/#!msg/clojure/JU6EmjtbRiQ/uND70kAFBgAJ
Ah, and there is also a brief answer in http://clojure.org's faq list here: https://clojure.org/guides/faq#instrument_ret
As I said, enough people find that answer unsatisfying that orchestra helps you do what many people would like to
Is there an idiom for using (try ...)
something like the following.
(try (value-or-throw-exception)
(catch ExceptionInfo e x1)
(catch AnotherException e x2)
(else-with v x3)
The idea is that if we catch a certain error then whatever x1
(or x2
) evaluates to is the value returned from try
. However, if no exception was thrown, then I want try to return x3
; but important is that the else-with
clause has access to the value returned from the first argument of try
?I am not aware of something like that built into Clojure's try/catch. It is straightforward to bind the return value of the entire try
expression to a let symbol, and then do further computation on that. The return value from the try could of course be written to make it clear whether an exception was caught by it or not, but that is not required behavior for a try
block -- you would have to write its contents to ensure that.
There are a few libraries people have written to provide macros that provide additional features over built-in try
, but I have not used them personally. slingshot is one such library: https://github.com/scgilardi/slingshot
(try (let [v (value-or-throw-exception)]
x3)
(catch ExceptionInfo e x1)
(catch AnotherException e x2))
I guess 🙂Good suggestion Timur.
obvious when you look at it.
another gotcha to bring up since this is #beginners : finally
clause runs last, but is not the return value of the try form
Funny enough, one CL habit which is excessively hard to break is to use ~ it interpolate a value into a backquote. I almost always first type
`(a b ,c d)
rather than
`(a b ~c d)
to me the , syntax is really hard wired deep in my brain. Not complaining, just commenting about habits being hard to break.This is one example that caused me to make that comment about American vs. British English -- so similar, yet so crucially different in a few ways that become automatic when using only one or the other for a long time 🙂
There is an early talk by Rich Hickey on Clojure, given to an audience of Common Lisp and Scheme users, where many questions are raised, and answers given, about why he designed some things to be explicitly different than those.
I understand the motivation, and agree with it. we want comma to be white space. its a good decision. I just need to get used to it.
is there some case where using the empty set #{} as a function and calling it with some value should return null
?
When debugging my program, this seems to happen, but I cannot reproduce it in the repl.
clojure-rte.core> (let [done #{}
pattern '(:* (:or Byte Integer Long Short))]
(done pattern))
nil
This returns nil
as expected.
But in this function: the println done prints #{}, and (done pattern)
prints as null
then I get an execution error.
(defn find-all-derivatives [pattern]
(println (format "find-all-derivatives %s" pattern))
(loop [to-do-patterns (list pattern)
done #{}
triples []
]
(println (format " to-do-patterns = %s" to-do-patterns))
(println (format " empty? = %s" (empty? to-do-patterns)))
(println (format " done = %s" done))
(println (format " triples = %s" triples))
(if (empty? to-do-patterns)
[ triples (seq done)]
(let [pattern (first to-do-patterns)
to-do-patterns (rest to-do-patterns)]
(println (format " pattern = %s" pattern))
(println (format " (type done) = %s" (type done)))
(println (format " (done pattern) = %s" (done pattern)))
(if (done pattern)
(recur to-do-patterns done triples)
(letfn [(xx [[acc-triples acc-derivs] wrt-type]
(let [triples (derivatives-narrow pattern wrt-type)]
;; triples is a seq of triples each triple is of the form [pattern wrt-type deriv]
[(concat acc-triples triples)
(concat acc-derivs (remove done (map (fn [s] (s 3)) triples)))]
)
)]
(let [[new-triples new-derivatives]
(reduce xx [[] ()] (first-types pattern))]
(recur (concat new-derivatives to-do-patterns)
(conj done pattern)
(concat triples new-triples)))))))))
prints the following
clojure-rte.core> (rte-compile '(:* int?))
find-all-derivatives (:* (:or Byte Integer Long Short))
to-do-patterns = ((:* (:or Byte Integer Long Short)))
empty? = false
done = #{}
triples = []
pattern = (:* (:or Byte Integer Long Short))
(type done) = class clojure.lang.PersistentHashSet
(done pattern) = null
Execution error (IndexOutOfBoundsException) at clojure-rte.core/find-all-derivatives$xx$fn (form-init16272114045093011175.clj:794).
null
clojure-rte.core>
I don't understand why (done pattern)
returns null, but it turns out that's not the problem in my program. The problem was my call to (s 3)
should be (s 2)
to retrieve the 3'rd element from an array. 0-based...
What do you not understand -- why it is printed as null and not as nil? That's because you're using format
(that stringifies any of nil
, 'null
and "null"
as "null", so perhaps it's not the best choice for debug prints?)
ah, it's just a printing issue.. cool cool cool
What's the simplest/most idiomatic way to check that stest/check
is passed in deftest?
(deftest scale-test
(is (empty?
(failures
(stest/check
common/scale)))))`
So far I could only found a guy on Github with this boilerplate function in his test utils namespace:
(defn failures
"Get any failing results of stest/check"
[check-results]
(mapv
(fn [{:keys [spec clojure.spec.test.check/ret sym failure] :as x}]
[sym
(-> x
(update :spec s/describe)
(dissoc :sym)
;; Dissoc the top level trace, leave the shrunken one
(update stc-ret dissoc :result-data))])
(remove #(-> %
stc-ret
:result
true?)
check-results)))
Is it the way to go? Can't find it in the core
https://github.com/dakra/mui-templates/blob/master/src/mui_templates/main.cljs#L141
where is that keyword :>
coming from? how can I find it out in general where these come from? It's impossible to google it
check out https://github.com/reagent-project/reagent/blob/master/doc/InteropWithReact.md
is this reagent specific? Again, my real question is, how to find out what something like this does?
I am grateful for the solution for the problem at hand, but would like to learn fishing, not just eat a fish 😄
you're passing a keyword (`:>`) to a library. that library is free to interpret that keyword as it pleases. the answer is you can't know just by looking at the data itself
It is reagent specific as far as I know, but may be used somewhere I haven't seen. I don't believe vanilla Hiccup supports that syntax. A good strategy for finding documentation on hard to google expressions might be searching the repos of the library that the expression belongs to
Mithchell: I tried to search on github, but couldn't, I would have to clone the whole thing and do some kind of local search, but thanks I will keep this option in mind.
@U5LPUJ7AP I am not quite sure if I understand you correctly. Where can I see that "I am passing" "to a library" this keyword, I only saw it as a function definition that was passed to react-dom, I still don't quite understand how it gets resolved to what the documentation linked by Mitchell is saying.
all of this is much simpler than you think. If I call a function with a keyword, that function is free to do whatever it pleases with it. it doesn't "resolve" to anything by itself. it doesn't mean anything. the library gives it meaning.
in this case the code that does this transformation is there: https://github.com/reagent-project/reagent/blob/2027a2d8881bae0567ecf9d4c90550b064a2ad0c/src/reagent/impl/template.cljs#L366
as you can see, ">" is hardcoded there to mean something, that's it
that code is basically "if the tag is equal to :>
then do this special native component thing, otherwise proceed normally"
> Where can I see that "I am passing" "to a library" this keyword,
in the example you link to, main-shell
is a function that returns a nested data structure that contains that keyword (`:>)` somewhere inside of it, at some point this structure is given to reagent/render
and it interprets this keyword
> as passed to react-dom,
it is passed to reagent.dom
(which is the library we just linked to)
thanks for elaborating on this, it helps a lot! indeed I confused reagent.render with reactdom.render : ( So I didn't even check if reagent has it.
how can it choose an element of a set which I know is not empty, I don't care which one?
I tried the following: (some identity the-set)
but it sometimes fails, for example (some identity #{false})
(first #{false})
first
that's good. I had been using the following: (reduce (fn [acc item] (reduced item)) identity #{false})
another thing to consider: (rand-nth (seq s))
Is there a type in clojure which every object is a member of?
something like T or Any or Everything ????
The JVM has class Object, that all other objects are sub-classes of.
But I suspect you are asking about more than that, given your earlier questions about isa? behavior.
is the type of x a subtype of Object for every x ?
I am not sure if I know what you mean precisely by the word 'subtype'. I can say that (instance? java.lang.Object x)
is true for every JVM object x
, and Clojure does not provide a way to pass a JVM primitive type to that call.
I think it is the same to say, for any given x, is (instance Object x)
guarnateed to return true? or is thes some exception? Like null
or nil
etc etc etc
Hmm I see that (instance? Object nil)
returns false
right, you beat me to that, so good for trying it out in the REPL 🙂
So is there a type above Object?
Again, not sure what you mean by 'type' here, again because of my lack of familiarity with Clojure isa?
. There is no more wide class in the JVM than Object
Clojure nil
is Java null
, which is not an instance/object of any kind. It is the lack of an instance/object of any kind.
(type nil)
returns nil
which other objects have nil
as a type ? I'm supposing that every object either has type Object
or type nil
????
user=> (type 5)
java.lang.Long
yes but (instance? Object 5)
returns true
so 5 is an instance of type Object
because java.lang.Long
is a subclass (perhaps through multiple other classes -- I do to recall off the top of my head, but Java docs make it quick to find out) of java.lang.Object
e.g. This Java doc page shows the class hierarchy of java.lang.Long
: https://docs.oracle.com/javase/7/docs/api/java/lang/Long.html
my understanding is that Object is a supertype of every type. except apparently the type which nil
is an instance of.
nil
in the JVM is not an instance of any type, is I believe a correct statement.
Well, null
is its name in Java source code.
but it seems I cannot pass null
to a clojure function. for example (type null)
triggers an error
BTW what's the relation of nil
and null
in clojure?
If you do (source type)
in a REPL, you will see that it in some cases calls function class
, and (source class)
shows that it returns nil given nil, and otherwise whatever the JVM method getClass
returns. Java docs for method getClass
shows that it returns an object of type java.lang.Class
Java null
is exactly Clojure nil
Except Java null
was named first, of course.
null
in Clojure is not a special name for anything - you can def
it, for example, and it will by like def
ing any other non-special name.
user=> (def null [1 2])
#'user/null
user=> null
[1 2]
really good to know. I had no idea. Sometimes things print as null.
user=> (def true [1 2])
Syntax error compiling def at (REPL:1:1).
First argument to def must be a Symbol
user=> (def nil [1 2])
Syntax error compiling def at (REPL:1:1).
First argument to def must be a Symbol
If some things print as null
, that is likely because of the function being used to do the printing is based on a JVM method that prints it as the string "null"
That should never happen if the function being called claims to print data in a Clojure-readable way, but not all functions claim to do that.
In general, Clojure in many cases does not attempt to hide the existence of the JVM from you. Just as ClojureScript in many cases does not attempt to hide the JavaScript runtime engine from you.
Straightforward interop with the host runtime is a design goal, not an accident.
got it
so what's the correct way to print something for debug without having it print as null?
(printf "%s\n" (seq #{}))
prints a null
Quick tests show these print nil as "nil": print, println, pr, pr-str
Also pprint
but pprint doesn't allow string interpolation. right?
Not all of those will print in a way that clojure.core/read will read, by the way -- but they do all print nil as "nil"
None of those work like printf does, no.
If I want to do something like: (printf "x = %s\n" x)
is that correct? or is there a better way?
I mean, if you like printf, and just remember that null in its output is Java null, which is identical to Clojure nil, then you should be ok with printf.
(println "x =" x)
is not interpolation, but gives similar results as your example printf call
yes you're right.
looks like (cl-format true "x=~A~%" x)
prints it as nil
pr-str might be useful to you here as well:
user=> (printf "%s\n" (pr-str nil))
nil
(defn clj-printf [fmt & params] (apply printf fmt (map pr-str params)))
- this also escapes strings though
But you have a bunch of primitive types likes int, array, long, and all and they don't have a common supertype
And I think null isn't part of the type system. All types can have the value null, so that's how null is handled I think. Like null is part of all sets of possible values of all types
I thought null was a property of a place not a type, and all places could be null
the jvm "type system" isn't even trying to be particularly consistent
beyond the OO conceit that all things inherit from Object (which is disregarded as desired for performance)
In Java, there are primitives and objects (which includes arrays). All objects extend from Object. There is no "type" that includes both objects and primitives. null is part of the type system - there is a special null type and null is the only value of that type. The null type is a subtype of all other reference types (except the null type). (It's not a proper bottom type as I understand it as it has one special null value, not no values.)
the Java Language Spec is pretty readable about all this stuff and worth reading if you are diving into this stuff.
@U064X3EF3 which java primitives are values in clojure?
There are special situations where you can get Clojure to emit JVM byte code that uses Java primitive long and double values, and maybe also some others, but quite often boxed Long and Double values are used instead.
boolean, char, long, and double are really the main ones Clojure uses (and typically does not use byte, short, int, or float), but as Andy said, those are all typically boxed into their object forms
IFn, the primary function interface, will always take and return objects. type hinting is required to coax it into taking or returning primitive longs or doubles
within the scope of a let or loop/recur (actually both supported by the same compiler code), the compiler plays some tricks to retain primitives if possible
@U064X3EF3, I'm not sure my question was clear. You implied earlier that java has Objects and primitives, but I see that 1.0 is an instance of type Object
. (instance? Object 1.0)
returns true
.
So is there another clojure object which is not an Object
, other than nil
. (instance? Object nil)
returns false
.
if 1.0 is at the top level of a normal form, it is not a primitive, it's the boxed Double
the compiler can generate and use the primitive version where it can prove it's possible and knows it's useful, but that doesn't include arguments to instance?
so literally a primitive can't be passed to the instance? function
Is there a function that just returns the element if it exists in a list? I know that I can do effectually the same thing with some
, but I wanted to know if there's a core function that operates like
(defn is-in?
[x lst]
(some #(= x %) lst))
You can use every-pred
https://clojuredocs.org/clojure.core/every-pred
Sorry, I think my question was confusing. I wanted to know if I could test for the presence of an element in a list, not whether a predicate returns true.
Otherwise I'd just use some
.
or (some = lst)
. [edit: as pointed out below, this does not work]
Oh, I understand
So, you can use contains?
https://clojuredocs.org/clojure.core/contains_q
Huh? I don't understand how that would work @U7RJTCH6J. Doesn't =
need two parameters, not one?
for all values except nil and false, #{x}
acts as a function that returns x if provided x as an argument
haha, whoops
OK, that's fine, I'll just use some
. I just wanted to know if there was a special function that tested for the presence of an element.
(cmd)user=> (some #{:a} [:c :d :a :e :b])
:a
(cmd)user=> (some #{:a} [:c :d :e :b])
nil
regarding contains?
(ins)user=> (contains? '(:a :b :c) :b)
Execution error (IllegalArgumentException) at user/eval214 (REPL:1).
contains? not supported on type: clojure.lang.PersistentList
(cmd)user=> (contains? [:a :b :c] :b)
false
(ins)user=> (contains? [:a :b :c] 1)
true
The examples and comments on the http://ClojureDocs.org page for contains? looks pretty accurate to me.
yes - I was warning against a suggestion offered above, since it's a common new user trap
When contains?
is applied to a vector, it returns whether the vector contains a value at the location (which is assumed to be a number), since vectors can basically be thought of as maps that are keyed in by index value.
Thanks @U051SS2EU! Very tricky