I have a custom macro defcall that expands into a defn, but it's always variadic (in a way that isn't evident from the macro arglist).
I am trying to get clj-kondo to stop bugging me about the arity. The config.edn entry is:
{:config-in-call {my.ns/defcall {:linters {:unresolved-symbol {:exclude [opts]}, :invalid-arity {:level :off}}}}, :lint-as {my.ns/defcall clojure.core/defn}}
What's wrong with that ? The :unresolved-symbol bit is working fine, and I believe it is linting as a defn.
Thanks for any insights ...It would be helpful if you had any examples of call sites where clj-kondo complains and you want to silence those
Yeah, I'm trying to figure out how to give you that - I can't simply paste my code.
The calls to defcall always look something like this:
(defcall mycall
"docs"
{:rate-limit {:base 10 :mid 15 :max 20}}
[ids]
(println "hi"))But then any place that mycall is called with > 1 argument, I get a clj-kondo warning:
src/clj/dev.clj:262:18: error: my.ns/mycall is called with 5 args but expects 1ok got it, let me try to repro this locally
Thank you!
So given this:
(ns dude)
(defmacro defcall [] :whatever)
(defcall mycall
"docs"
{:rate-limit {:base 10 :mid 15 :max 20}}
[ids]
(println "hi"))
(mycall 1 2 3)
{:config-in-call
{dude/defcall {:linters {:unresolved-symbol {:exclude [opts]},
:invalid-arity {:level :off}}}},
:lint-as {dude/defcall clojure.core/defn}}
$ clj-kondo --lint dude.clj
dude.clj:8:4: warning: unused binding ids
dude.clj:11:1: error: dude/mycall is called with 3 args but expects 1
linting took 7ms, errors: 1, warnings: 1
It's the error that bothers you right? The issue is that mycall isn't a call "in" dude/defcall, but you're calling something produced by defcall.
The only good solution here is to use a hook that expands the defcall call to something which actually spits out a defn with a varargs signature.Yeah, that's it. I was already reading the hooks docs, and it'll probably be good for me to learn it. I was just avoiding it since then I have to set up my library to explicitly export this information so downstream projects can pick it up.
Thanks for your help!
the :macroexpand hook is probably the easiest to start with
Potential false-positive on conj!
Is there anything wrong with this?
(defn x []
(let [items (transient [])]
(doseq [item [:a :b :c]]
(conj! items item))
items))Because I get an Unused value warning on this
I think you need to grab the return value of conj!
conj! is not "bash in place", it is the same model as conj - use the return
Then I used it completely wrong for the whole time, but it is working like that
Is that by just an accident?
it will "work" up to 8 items but then it will very much not work
or maybe it's 32 items, can't remember the break
I collected 40 items without issues 🙂
60% of the time it works every time 🙂
Thank you! TIme to fix a potential bug in the production code as well then
it's 8 for maps (ArrayMap -> HashMap)
(defn x [n]
(let [items (transient {})]
(doseq [item (range n)]
(conj! items [item item]))
(persistent! items)))
(x 9)I was using sets, and I could collect 40 items easily with that
In any case, you should not
it is an extremely common mistake to make with transients which is a real bummer
it looks like ATransientSet notices if the backing map changes and always just returns this, which might explain why you didn't run into problems with sets. But I'd say this is a happy little accident rather than something you should rely on.
Sure thing, I’ve already fixed the code
the docstring for transient was updated in 1.12 to mention this
I can see that, now: > Note in particular that transients are not designed to be bashed in-place. You must capture and use the return value in the next call. In this way, they support the same code structure as the functional persistent code they replace.
Most of the time I am using the http://clojuredocs.org offline dump, which has not been updated for awhile now
Anyways, thank you TIL!