Welcome! Please see the About page for a little more info on how this works.

0 votes
in Compiler by

I would have expected that both of the Java interop calls below would avoid reflection, but only the first involving f1 does.

`
Clojure 1.6.0
user=> (set! warn-on-reflection true)
true
user=> (defn f1 ^java.util.LinkedList [coll] (java.util.LinkedList. coll))

'user/f1

user=> (def f2 (fn ^java.util.LinkedList [coll] (java.util.LinkedList. coll)))

'user/f2

user=> (.size (f1 [2 3 4]))
3
user=> (.size (f2 [2 3 4]))
Reflection warning, NO_SOURCE_PATH:5:1 - reference to field size can't be resolved.
3
`

Not sure if this has anything to do with CLJ-1232, but was discovered when testing variants of that issue.

8 Answers

0 votes
by

Comment made by: jafingerhut

What a nice number for a ticket, 1543. The year Copernicus's most celebrated book was published: http://en.wikipedia.org/wiki/Nicolaus_Copernicus

0 votes
by

Comment made by: wagjo

Isn't type hinting of arg vector meant only for primitive type hints? AFAIK non-primitive type hints should be on a function name, everything else is non idiomatic.

0 votes
by

Comment made by: bronsa

This isn't an issue of arg vector hinting vs function name hinting.
The issue here is that return type hinting cannot be put on anonymous functions but only on defns as the :arglists will be added by defn on the Var's metadata.

This is one of the reasons why I'd like to have that information as a field on the fn rather than as metadata on the Var

0 votes
by

Comment made by: jafingerhut

Jozef, you may be correct that non-primitive type hints on the argument vector are non idiomatic. Do you have any source for that I could read?

0 votes
by

Comment made by: tsdh

Only the version with hints on the argument vectors is documented at http://clojure.org/java_interop#Java Interop-Type Hints. However, in the case you have just one arity (or all arities return a value of the same type) the hint on the var name also works. But the two versions seem to have different semantics. Have a look at CLJ-1232.

0 votes
by
_Comment made by: wagjo_

Type hinting is a very intricate part of Clojure but you can almost always apply a *'place hint on a symbol'* idiom. Type hinting on an arg vector must be done only in two cases:
- primitive hints
- different return classes for different arities

In the first case, compiler needs type hints when compiling fn* (see [1]), not later, thus you must specify them on arg vector.

Second case, which is the issue discussed here, must be used only when defining with defn. Compiler first looks for the tag in the metadata of a var, and if it does not find one, it has a special case in which it looks for a return class inside :arglist metadata. This is clearly a very special case [2] to handle situations where you have different return classes for different arities. Obviously, using def instead of defn won't create an :arglist metadata for you thus you see a reflection warning. Example:


user=> (def f2 (fn ^java.util.LinkedList [coll] (java.util.LinkedList. coll)))
#'user/f2
user=> (.size (f2 [2 3 4]))
Reflection warning, /tmp/form-init.clj:1:1 - reference to field size can't be resolved.
3
user=> (alter-meta! #'f2 assoc :arglists '(^java.util.LinkedList [coll]))
{:ns #<Namespace user>, :name f2, :file "/tmp/form-init.clj", :column 1, :line 1, :arglists ([coll])}
user=> (.size (f2 [2 3 4]))
3


BTW CLJ-1491 has a discussion slightly relevant to this topic.

[1] https://github.com/clojure/clojure/blob/03cd9d159a2c49a21d464102bb6d6061488b4ea2/src/jvm/clojure/lang/Compiler.java#L5134
[2] https://github.com/clojure/clojure/blob/03cd9d159a2c49a21d464102bb6d6061488b4ea2/src/jvm/clojure/lang/Compiler.java#L3572

0 votes
by

Comment made by: wagjo

Andy, I've found sources that speak against my recommendations :) See CLJ-811 and (link: 1).

(link: 1) https://groups.google.com/d/msg/clojure/b005zQCPxOQ/6G0AlWKKKa0J

0 votes
by
Reference: https://clojure.atlassian.net/browse/CLJ-1543 (reported by jafingerhut)
...