Why is this using reflection?

3 views
Skip to first unread message

tsuraan

unread,
Jun 5, 2009, 5:26:05 PM6/5/09
to clojure
I have a function to get the path out of a lucene searcher
(documentation at
http://lucene.apache.org/java/2_3_2/api/core/org/apache/lucene/search/IndexSearcher.html).
The searcher has a Reader, which has a Directory. The Directory is
abstract, but in my case I know that it's a FSDirectory, so I declare
fsdir, and then use its getFile and getPath. The actual code I'm
using is:

(defn searcher-path [ #^IndexSearcher searcher ]
(let [fsdir #^FSDirectory (.. searcher getIndexReader directory)
path #^String (.. fsdir getFile getPath) ]
path))

When I compile this with warn-on-reflection, I get that getField and
getPath cannot be resolved. Am I doing the hinting wrong somehow? I
do have imports in my file for IndexSearcher and FSDirectory, so I'm
not sure what I'm missing.

I've also tried this with nested lets, but that didn't help either (as
expected).

Chouser

unread,
Jun 8, 2009, 8:53:39 AM6/8/09
to clo...@googlegroups.com

I thought it might be fun to try out the new repl-utils expression-info fn on
this.

So first I had to recreate your 'import' line (you might consider including this
kind of detail next time you post a question):

(import '(org.apache.lucene.search IndexSearcher)
'(org.apache.lucene.store FSDirectory))

Then in order to use expression-info, I had to adjust your code to make it
a stand-alone expression that returns the value I care about. Then I wrapped it
in a call to expression-info:

(expression-info
'(let [#^IndexSearcher searcher nil] ; replaced 'defn' with simple 'let'


(let [fsdir #^FSDirectory (.. searcher getIndexReader directory)
path #^String (.. fsdir getFile getPath)]

path)))

This just returns 'nil', which is what I'd expect since the reflection warning
already told us the compiler doesn't know the type. So lets cut out the parts
producing the warning:

(expression-info
'(let [#^IndexSearcher searcher nil] ; replaced 'defn' with simple 'let'
(let [fsdir #^FSDirectory (.. searcher getIndexReader directory)]
fsdir)))

returns:

{:class org.apache.lucene.store.Directory, :primitive? false}

Now this is interesting. I thought we'd specifically told it fsdir was an
FSDirectory, but the complier seems to think it's just a Directory. It appears
to be taking the actual return type of the directory() method over our type
hint. I don't know if this is a feature or a bug, but perhaps we can be a bit
more insistent. What happens if we type-hint the local directly instead of the
expression?

(expression-info
'(let [#^IndexSearcher searcher nil] ; replaced 'defn' with simple 'let'
(let [#^FSDirectory fsdir (.. searcher getIndexReader directory)]
fsdir)))

returns:

{:class org.apache.lucene.store.FSDirectory, :primitive? false}

Well, that seems to have done it. Using that style in the original expression,
we get:

(defn searcher-path [#^IndexSearcher searcher]
(let [#^FSDirectory fsdir (.. searcher getIndexReader directory)
#^String path (.. fsdir getFile getPath)]
path))

That compiles without reflection warnings.

Note also that hinting 'path' as 'String' doesn't really do any good when all we
do is return it:

user=> (expression-info '(searcher-path nil))
nil

If you want to promise that 'searcher-path' will always return a String so that
the compiler can make further type deductions based on that, you need to hint
the function itself:

(defn #^String searcher-path [#^IndexSearcher searcher]
(let [#^FSDirectory fsdir (.. searcher getIndexReader directory)]
(.. fsdir getFile getPath)))

user=> (expression-info '(searcher-path nil))
{:class java.lang.String, :primitive? false}

--Chouser

tsuraan

unread,
Jun 8, 2009, 11:41:04 AM6/8/09
to clo...@googlegroups.com
> I thought it might be fun to try out the new repl-utils expression-info fn
> on
> this.

Is this just in source control, or is it in a release? I'm using
1.0.0, and I don't seem to have that function.

> So first I had to recreate your 'import' line (you might consider including
> this
> kind of detail next time you post a question):

Yeah, sorry about that. I'll remember next time.

> Well, that seems to have done it. Using that style in the original
> expression,
> we get:
>
> (defn searcher-path [#^IndexSearcher searcher]
> (let [#^FSDirectory fsdir (.. searcher getIndexReader directory)
> #^String path (.. fsdir getFile getPath)]
> path))
>
> That compiles without reflection warnings.

I thought I had tried this and gotten an error for it; I must have
made a typo and assumed it was an invalid thing to do. It's certainly
working now :) Where can I get more info on the expression-info call?
A google search for "expression-info" and clojure gives a pdf on
multiple dispatch and nothing else.

> Note also that hinting 'path' as 'String' doesn't really do any good when
> all we
> do is return it:

That's really strange. The clojure compiler doesn't put types on
functions when the only value returned from a function has an explicit
type?

> user=> (expression-info '(searcher-path nil))
> nil
>
> If you want to promise that 'searcher-path' will always return a String so
> that
> the compiler can make further type deductions based on that, you need to
> hint
> the function itself:
>
> (defn #^String searcher-path [#^IndexSearcher searcher]
> (let [#^FSDirectory fsdir (.. searcher getIndexReader directory)]
> (.. fsdir getFile getPath)))
>
> user=> (expression-info '(searcher-path nil))
> {:class java.lang.String, :primitive? false}

In the type hinting page, it says type hits can be applied to function
parameters, let-bound names, var names and expressions. Is the
#^String here being applied to a var name (searcher-path)? It wasn't
obvious to me that one could do that, although I guess functions names
are variables just like any other names in the system.

J. McConnell

unread,
Jun 8, 2009, 11:51:13 AM6/8/09
to clo...@googlegroups.com
On Mon, Jun 8, 2009 at 11:41 AM, tsuraan <tsu...@gmail.com> wrote:

> I thought it might be fun to try out the new repl-utils expression-info fn
> on
> this.

Is this just in source control, or is it in a release?  I'm using
1.0.0, and I don't seem to have that function.

tsuraan

unread,
Jun 8, 2009, 12:22:29 PM6/8/09
to clo...@googlegroups.com

Yup, that certainly does help :) Thanks!

Reply all
Reply to author
Forward
0 new messages