This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2023-06-01
Channels
- # announcements (20)
- # babashka (3)
- # beginners (30)
- # calva (28)
- # cider (3)
- # circleci (4)
- # clerk (27)
- # clj-kondo (72)
- # cljdoc (15)
- # cljs-dev (1)
- # clojure (85)
- # clojure-europe (37)
- # clojure-nl (1)
- # clojure-norway (13)
- # clojure-spec (7)
- # clojurescript (19)
- # clr (1)
- # conjure (11)
- # datahike (2)
- # datomic (11)
- # emacs (26)
- # events (4)
- # hoplon (35)
- # hyperfiddle (41)
- # jobs (7)
- # lsp (10)
- # nrepl (3)
- # off-topic (57)
- # portal (47)
- # practicalli (1)
- # rdf (3)
- # reitit (21)
- # releases (1)
- # testing (6)
- # tools-build (16)
- # wasm (1)
- # xtdb (16)
Using clj-kondo v2023.05.26, given a little bb script alana.clj
(ns alana
(:require [babashka.process :as p]
[clojure.edn :as edn]
[clojure.pprint :as pprint]))
(let [code (first *command-line-args*)
config {:config-paths ^:replace []
:analysis {:var-definitions {:meta true}
:arglists true}
:output {:format :edn}}]
(-> (p/shell {:in code
:continue true
:out :string}
"clj-kondo"
"--config" (binding [*print-meta* true] (pr-str config))
"--lint" "-")
:out
edn/read-string
:analysis :var-definitions
pprint/pprint))
If I analyze a simple defn, I get back the :arglist-strs
I would expect:
โฏ bb alana.clj '(defn foo [x])'
var analysis for code: (defn foo [x])
[{:fixed-arities #{1},
:end-row 1,
:meta nil,
:name-end-col 10,
:name-end-row 1,
:name-row 1,
:ns user,
:name foo,
:defined-by clojure.core/defn,
:filename "<stdin>",
:col 1,
:name-col 7,
:defined-by->lint-as clojure.core/defn,
:end-col 15,
:arglist-strs ["[x]"],
:row 1}]
(The encoding of arglists to strings seems like a good design choice to me, btw; no worries about edn encoding/decoding.)
But if I try to analyze some code where I override :arglists
with metadata like so:
โฏ bb alana.clj $'(defn foo {:arglists \'([y])} [x])'
var analysis for code: (defn foo {:arglists '([y])} [x])
[{:fixed-arities #{1},
:end-row 1,
:meta {:arglists '([y])},
:name-end-col 10,
:name-end-row 1,
:name-row 1,
:ns user,
:name foo,
:defined-by clojure.core/defn,
:filename "<stdin>",
:col 1,
:name-col 7,
:defined-by->lint-as clojure.core/defn,
:end-col 34,
:arglist-strs ["[x]"],
:row 1}]
My observations are that:
1. I do see the overridden :arglists
under :meta
2. The :arglists
under meta does not have the same string encoding as :arglist-strs
(nor do we have an :arglist-strs
under meta)
3. The overridden :arglists
are not applied to :arglist-strs
This is not a complaint. Just a thing I noticed while exploring static API analysis for cljdoc.
If this is expected and intended behaviour, then I shall carry on with that understanding.
If it is unintended behaviour, lemme know, I can raise at least raise an issue.I see, a lotta words without a question.... Apologies @U04V15CAJ, so the question is, I suppose, should arglists overridden by metadata be applied to :arglist-strs
?
I think arglists-strs is how the arglist is written and metadata contains additional arglist if supplied as meta?
$ clj-kondo --lint /tmp/arg.clj --config "{:analysis {:var-definitions {:meta [:arglists]}} :output {:format :edn}}" | jet -t ':analysis :var-definitions'
[{:col 1,
:defined-by clojure.core/defn,
:defined-by->lint-as clojure.core/defn,
:end-col 5,
:end-row 4,
:filename "/tmp/arg.clj",
:fixed-arities #{1},
:meta {:arglists (quote [y])},
:name foo,
:name-col 7,
:name-end-col 10,
:name-end-row 1,
:name-row 1,
:ns user,
:row 1}]
@UE21H2HHD I'm doing this in quickdoc: https://github.com/borkdude/quickdoc/blob/db61b35b613d3c1a7e84ea96efab6827cca20406/src/quickdoc/impl.clj#L109-L114
Thanks @U04V15CAJ, so the behaviour is as intended. That works for me. Just wondered if I had found something that was unintended.
Thanks, that makes sense. Do you remember why you decided to go with :arglist-strs
instead of :arglists
? I'm guessing that the string encoding helped to avoid forms that might not be edn-readable?
Like for odd stuff: (defn foo [{:keys [:bar :baz] :or {bar #"regex"}}])
:arglist-strs
preserves all just fine: ["[{:keys [:bar :baz] :or {bar #\"regex\"}}]"]
But if we have same as meta: (defn foo {:arglists '([{:keys [:bar :baz] :or {bar #"regex"}}])} [x])
:meta
:arglists
is a bit off: ([{:or {bar (re-pattern "regex")}, :keys [:bar :baz]}])
I suppose this is pretty edge-casey.
right, I think arglists-strs is for showing and maybe it makes sense to override it from meta
What do you think @UKFSJSM38?
:arglists
treatment different from :doc
. For :doc
we always see :doc
overridden by metadata in root var map. But for :doc
, unlike :arglists
, an original value is never interesting.
Yes, it's only for showing in clojure-lsp if one hover or ask the docs of a function that has the arglists meta, so it would work as well for lsp
So is original (un-overridden value) of :arglists
ever interesting tho? (It isn't for my use case).
for LSP it is, as it checks for the meta arglists, if not present, use the root arglists-strs
it is only for clj-kondo to deduce the arities, but I don't think clj-kondo makes use of that API
@UKFSJSM38 I think what you are using arglist-strs for is just for showing info, you're never interested in the "original", e.g. if a user writes:
(defn foo {:arglists '([x y z])} [& xs])
you are only ever interested in [x y z]
, not in [& xs]
@U04V15CAJ, I assume arities are deduced from ([x y z])
and not [& xs]
, amiright?
Confirmed @U04V15CAJ, you are correct
It:s not only hover info, but completion, call hierarchy, signature help and other features, but all to present info only
it often uses informal notation like '([xs* xs?)]
which is garbage for deducing arity info
So I can write up an issue @U04V15CAJ, but in a nutshell :arglist-strs
should be overriden by any :arglists
metadata. Zat the idea?
> no, :arglists metadata can't be trusted for arities @U04V15CAJ can :arities metadata be trusted for arities of def's?
(def ^{:arities #{1 2}} f ...)
yes, there is only :inline-arities metadata in use
but I wish to be able to say kondo about arities for functions defined via def
so we could utilize :arities similar to :inline-arities
Some occurrences in the wild: https://grep.app/search?q=def%20%5E%7B%3Aarglist
@UE21H2HHD These are :arglists
, not :arities
- you weren't reacting to arities I guess?
so :arglists metadata works fine for documenting def
s and defmulti
a (and other macros which generates global functions) but unfortunately kondo don't check arities in these case what is sad ๐
@U0HJNJWJH it would cause false positives which is even sadder
I guess clj-kondo could do a best effort attempt: if arglists only has regular symbols and not *
or ?
in the name, try to deduce arity info from it. But why the hassle, just define a wrapper function with a proper docstring + arglist using defn
: this is what I do in my own libs, tools.build also does it, etc
> it would cause false positives which is even sadder that's why I offer some specific way to say correct data to kondo like :arities
> define a wrapper function this sounds suboptimal for me, to generate new java class and add level of indirection just for documentation purpose ๐ I'll better live without arity check from kondo side
if you avoid writing a function because you'll save a Java class, you're optimizing for the wrong thing in a functional language like Clojure if you ask me ;)
I've been pondering a different solution for the above problem. If you write:
(def foo impl/foo)
clj-kondo could just inherit the arity information from impl/foolet's narrow to defmulti case do you see a way to define multi-fn and teach kondo about it's arity?
it is this issue: https://github.com/clj-kondo/clj-kondo/issues/412 feel free to comment + upvote
I mean, not about defmulti, just the (def foo iml/foo)
, you posted other stuff while I was searching this issue
other of defmulti there are other ways to define functions using various macros
so I don't mind to have clj-kondo specific way to provide arity information for linting
any global vars (dynamic, declared in advance...), like #_:clj-kondo/arity ...
etc.
I tend to have universal way, not just smart inheritance or similar But inheritance is good as well ๐
smart inheritance is in https://github.com/clj-kondo/clj-kondo/issues/412
I've also thought about a reader conditional for clj-kondo so you can specify what code clj-kondo should analyze instead of other code, or so. I'll keep thinking about it, thanks for your input
@U04V15CAJ, @UKFSJSM38 issue raised: https://github.com/clj-kondo/clj-kondo/issues/2096, I look forward to your review and feedback.
ah yes, I forgot that the :arglists
is something that is evaluated and there often quoted. so presenting it as is maybe doesn't make sense :-S
Yeah, we'd need to un-quote for :arglist-strs
https://github.com/borkdude/quickdoc/blob/db61b35b613d3c1a7e84ea96efab6827cca20406/src/quickdoc/impl.clj#L109-L114