Is this expected?
[~] clj
Clojure 1.12.0
user=> (set! *warn-on-reflection* true)
true
user=> (java.util.HashMap. {})
Reflection warning, NO_SOURCE_PATH:1:1 - call to java.util.HashMap ctor can't be resolved.
{}
user=> (java.util.HashMap. ^java.util.Map {})
Reflection warning, NO_SOURCE_PATH:1:1 - call to java.util.HashMap ctor can't be resolved.
{}
user=> (let [m {}] (java.util.HashMap. m))
Reflection warning, NO_SOURCE_PATH:1:13 - call to java.util.HashMap ctor can't be resolved.
{}
user=> (let [^java.util.Map m {}] (java.util.HashMap. m))
{}This? https://clojure.atlassian.net/issues/CLJ-1929 (says it was fixed in 1.12)
Looks like the alternative method-type-hinting approach was deemed a proper solution for this kind of problem.
Sad :(
I'd say yes. When you use ^ syntax on a literal, the metadata is associated to the data at runtime. In the generic case, the compiler can't resolve ^something {:arbitrary data} to do it in compile time.
Since it happens at runtime, the compiler doesn't know about the type tag you assigned to the literal.
no, this is read-time constant, same as symbol
{} is but {:something (+ 1 2} is not.
Yeah but I have {}
I'd have thought/assumed literal maps would already had type tags available for compiler in general as well.
I might be wrong about the reasoning. But I'm pretty sure that only symbols and lists ("round parens") can have compile-time metadata
That's one of the reasons why the compiler doesn't attach line numbers to vectors and maps
> I'd have thought/assumed literal maps would already had type tags available for compiler in general as well. Same
Even without metadata, compiler can see that it’s a map?
This is weird:
user=> (set! *warn-on-reflection* true)
true
user=> (java.util.HashMap. ^java.util.Map (identity {}))
{}> This is weird:
It is not. The type tag went onto (identity {}) form.
user=> (java.util.HashMap. ^java.util.Map (do {}))
Reflection warning, NO_SOURCE_PATH:1:1 - call to java.util.HashMap ctor can't be resolved.
{}do gets expanded very early by the compiler, it's the "specialest" of all forms
yes, it's all logical when you look into the compiler, but I can see why it's confusing to people who don't
Same with if, I guess? Because it all started with me trying to annotate if
anyway, just use a local I guess ;)
wait
user=> (^[java.util.HashMap] java.util.HashMap/new {})
Syntax error (IllegalArgumentException) compiling java.util.HashMap/new at (REPL:1:1).
Error - param-tags [java.util.HashMap] insufficient to resolve constructor in class java.util.HashMapI would be more surprised by if not retaining metadata than do, but it probably makes sense too
> I would be surprised > makes sense It’s one or the other
user=> (^[java.util.Map] java.util.HashMap/new {})
{}Oops
Yeah that makes sense
> Even without metadata, compiler can see that it’s a map? The compiler doesn't have a special check and type inference flow for the case where the user passed a literal empty map, yes:)
> It’s one or the other than is operative in that sentence
The compiler doesn't have a special check and type inference flow for the case where the user passed a literal empty map, yes:)No, it know it’s a map. Even run-time {...} literal will produce map in the end, type of which Compiler knows
Compiler knows, but doesn't use this knowledge
=> (Compiler/analyze clojure.lang.Compiler$C/EVAL '{})
#object[clojure.lang.Compiler$EmptyExpr 0x115eee10 "clojure.lang.Compiler$EmptyExpr@115eee10"]
The map is wrapped in a EmptyExpr by the analyzer. If the HostExpr analyzer were to peel this wrapper off, it would be able to use the class of the underlying object, yes. But it indeed doesn't.> Compiler knows, but doesn't use this knowledge I want this on a t-shirt!
https://ask.clojure.org/index.php/13339/tools-better-detect-errors-coming-existing-methods-fields
hmm that has less info than i remember
i remember a discussion about this but it must have happened on slack
I didn’t read all this thread but we have a ticket for the issue of not being able to type hint literal colls. The places where you need to do it are uncommon but it is frustrating when it happens and I think it should be fixable. On my phone, so not going to try to find it atm
And while we are on the topic, is this expected as well (can’t annotate ctors with param-tags):
[~] clj
Clojure 1.12.0
user=> (set! *warn-on-reflection* true)
true
user=> (defn f [s] (String. s))
Reflection warning, NO_SOURCE_PATH:1:13 - call to java.lang.String ctor can't be resolved.
#'user/f
user=> (defn f [s] (^[String] String. s))
Reflection warning, NO_SOURCE_PATH:1:13 - call to java.lang.String ctor can't be resolved.
#'user/f
user=> (defn f [s] (String. ^String s))
#'user/f(defn f [s] (^[String] String/new s))Oh
I believe the param-tags stuff is designed in conjunction with the qualified method stuff
Thanks, that helps solving my problem!