1. is there a syntax guide for Var meta :arglists
? things like clojure.core/eduction
have hand-written syntax '([xform* coll])
2. are there better ways to extract the arities from normal defn
s?
3. what ways there are to pull out return type hints per artities, besided Var :tag
meta - which is shared for all arities?
4. what ways there are to get argument type hints?
5. would it be possible to extract all the info (arities, basic type hints) programmatically in the future? e.g. compiler option to inject more info into Var & fn meta?
could use the stellar tooling from @borkdude (sci, edamame & clj-kondo), but as the clojure compiler knows all these already, would like to hear if it is possible to get access to that info directly
every argvec for each arity can specify an arity specific return type hint
the algo for return type is to first check on the argvec and fallback on the var type hint
for args it's per binding in the argvec of the specific arity
the compiler does no validation on 'correct' arglist format, so sometimes handmade ones are not in the right format and they're just ignored
afair there's no exposed api from the compiler to get this info
and no specification
(apologies for being terse, typing from a phone :) )
there is no formal spec and in the wild you can encounter things that deviate from what you see in core
in general, "locking" a var into a concrete set of arities immediately raises questions about what that means for future (additive) modifications to the signature
Well but the compiler does specialise interop calls according to the "current" arglist so it is locking in a way
ah, you said additive :) fair enough
> the compiler does no validation on 'correct' arglist format, so sometimes handmade ones are not in the right format and they're just ignored does the compiler do anything with the handmade arglists at all other than adding it to the metadata?
it doesn't know if it's handmade or installed by defn
it just looks for type hints if the arglist is present, if the format is incorrect it may ignore it or derive the wrong type hint at callsites
"it" = the clojure compiler?
ye
I'm surprised since I assumed that the "handwritten" arglists was just for documentation clarification
e.g. when you define a function using comp
or so
it serves two purposes, documentation and holds type hints
there was a proposal years ago about decoupling for this reason
so you could have a different arglist for documentation that doesn't need to be 'correct', while keeping the true one for the compiler
but as things are you just need to be careful if you're crafting a tyoe hinted arglist manually
which to be honest not many do anyway, apart from some instances in core
if you want to optimize you might as well write it out in full
so not particularly high value I'd say, even if the idea would be nice
optimise in what sense?
using type hints
sorry, being dense :) not following
e.g. when I define a function using comp
but I want some type hint optimization, I might as well not use comp
but write my fn using defn
ah, right
tools.analyzer
is just for analyzing source code, right? it’s awesome tool, but could the normal clojure compiler expose more info to the runtime? (via compiler option)
(->> (jvm/analyze
'(fn
([] "kikka")
([x] (inc x))
(^Boolean [x y] (+ x y))
([x y & zs] (apply + x y zs)))
(jvm/empty-env))
:methods
(mapv (fn [{:keys [arglist body tag params]}]
{:tag (or (:tag body) tag)
:arglist arglist
:args (mapv (fn [arg] (select-keys arg [:form :tag])) params)})))
;[{:tag java.lang.String
; :arglist []
; :args []}
; {:tag java.lang.Number
; :arglist [x]
; :args [{:form x, :tag java.lang.Object}]}
; {:tag java.lang.Boolean
; :arglist [x y]
; :args [{:form x, :tag java.lang.Object}
; {:form y, :tag java.lang.Object}]}
; {:tag java.lang.Object,
; :arglist [x y & zs],
; :args [{:form x, :tag java.lang.Object}
; {:form y, :tag java.lang.Object}
; {:form zs, :tag clojure.lang.ISeq}]}]
yeah sure, I wasn't suggesting using t.a
just pointing to that function to extract the relevant argvec for an arity, which more or less defines the syntax the compiler understands
Bronsa knows best, but my understanding is that the Clojure compiler might reveal some or all of this via JVM objects that it creates, but none of it is documented outside of the Clojure compiler source code (and perhaps someone's personal documentation notes), and none of it is promised not to change across versions of the Clojure compiler
this kinda thing:
(let [f (fn
([] "kikka")
([x] (inc x))
(^Boolean [x y] (+ x y))
([x y & zs] (apply + x y zs)))]
(pull-out-arities-and-types f))
no, the clojure compiler only uses arglists during a 'read' and analysis, it's not exposed in the ast
ah @ikitommi, arglists and type hints are on vars not functions
there's nothing reified on function objects for that
could there be?
so nothing you can do on lambdas apart from doing reflection over the class
there could, I believe there's a ticket in jira but no patch
but also not super useful, type hints are used at callsites, in a HOF setting they would not be analyzeable
unless doing complex flow analysis and per object specialisation which clojure doesn't do
(defn f
([] "kikka")
([x] (inc x))
(^Boolean [x y] (+ x y))
([x y & zs] (apply + x y zs))) )
(meta #'f)
;{:arglists ([] [x] [x y] [x y & zs]),
; :line 2331,
; :column 1,
; :file ...
; :name f,
; :ns ...}
that's on the var
it has arglists (which is good), but no type-info 😞
it does
really?
you need to print meta of the symbols and vectors
if you get the meta of [x y] from that arglists you'll see the boolean tag
oh, cool. didn’t know that, thanks!
… but the inferring of return types from the body is not there, needs t.a, right?
clojure doesn't do return type inference, it only does a simple form of local type inference (to specialise interop calls), but doesn't propagate across fn boundaries
t.a could, and with some minor enhancements so could the clojure compiler, but I believe it's a design decision not to
what the compiler does is super basic and, I believe, intentionally limited
remember they are type hints, not type declarations
there's at least one function in core that has a ^String type hint on an argument that could be a symbol, and to the compiler that's fine
(since that local is only used on an interop call after a string? check)
thanks for the great explanation. Couldn't find the relevant jira issue, only the SO question with few ways to resolve the fn arity at runtime. Would be great if core could expose those directly (in a dev-mode, as extra meta would consume memory)
https://stackoverflow.com/questions/1696693/clojure-how-to-find-out-the-arity-of-function-at-runtime
pluggable analyzing would solve both things: t.a could push out arity & infered type hints for both vars and fns.
TIL about arglists too, I also assumed they were just documentation.