areduce flaw

3 views
Skip to first unread message

Boris Mizhen

unread,
Apr 27, 2009, 4:26:12 PM4/27/09
to Clojure
Hello all,
It seems to me that areduce can not be used with an anonymous array.
Consider:

(areduce (.. System getProperties values toArray) i r 0
(some_expression))

It seems to me that there is no way to get i'th element of the array
in (some_expression) other than let'-ing it first.
It would be nice to be able to pass the name for the current element
or define a local macro that expands to
(aref #a i) - here #a is a gensym for the array itself ...

Thought?

Boris

Boris Mizhen

unread,
Apr 27, 2009, 5:17:40 PM4/27/09
to Clojure
I suspect I will be asking more questions, so in order not to start
another thread I will post below :)

Why
((comp - +) -3 -4) => 7

but

((comp Math/abs +) -3 -4) => Error?
java.lang.Exception: No such namespace: Math (NO_SOURCE_FILE:1)
[Thrown class clojure.lang.Compiler$CompilerException]

and
((comp #(Math/abs %) +) -3 -4) => 7

Is there an inherent difference between java and clojure functions, so
Java functions can't be passed as arguments? Or am I missing
something?

How can I pass a static java function to another function?

A member function must be trickier because this must be supplied, but
perhaps a macro can be created that results in a function that would
capture this and call the member function appropriately ...

Thank you,
Boris

Meikel Brandmeyer

unread,
Apr 27, 2009, 5:34:06 PM4/27/09
to clo...@googlegroups.com
Hi,

Am 27.04.2009 um 23:17 schrieb Boris Mizhen:

> ((comp #(Math/abs %) +) -3 -4) => 7
>

> How can I pass a static java function to another function?

Here you already gave the answer to your question. Wrap it in
a Clojure fn/#().

> A member function must be trickier because this must be supplied, but
> perhaps a macro can be created that results in a function that would
> capture this and call the member function appropriately ...

#(.someMethod an-object %)

Or passing in the object:

#(.someMethod %1 %2)

For apply and friends one needs a more elaborate way.
Search for "rhickey jcall site:paste.lisp.org".

Sincerely
Meikel

Boris Mizhen

unread,
Apr 27, 2009, 5:51:52 PM4/27/09
to Clojure
Hi Meikel, thanks for the answer.

I wonder if someone could explain or point me to the explanation about
*why* a Java static fn can't be passed just like a closure fn?

After all the syntax to call them is the same :)

Thanks,
Boris
>  smime.p7s
> 5KViewDownload

Kevin Downey

unread,
Apr 27, 2009, 5:56:56 PM4/27/09
to clo...@googlegroups.com
no, the syntax is not the same.

user=> (macroexpand-1 '(.foo bar))
(. bar foo)
--
And what is good, Phaedrus,
And what is not good—
Need we ask anyone to tell us these things?

Stuart Sierra

unread,
Apr 27, 2009, 6:46:58 PM4/27/09
to Clojure
On Apr 27, 5:51 pm, Boris Mizhen <bo...@boriska.com> wrote:
> I wonder if someone could explain or point me to the explanation about
> *why* a Java static fn can't be passed just like a closure fn?

The only reason I can give you is that Java methods aren't first-class
objects, like Clojure fns.

The (.method object) and (SomeClass/method ...) forms are syntactic
sugar, that expand to a special form:

user> (macroexpand '(.method object argument))
(. object method argument)
user> (macroexpand '(Class/method argument))
(. Class method argument)

Perhaps the compiler could automatically wrap Java methods when they
are used as a value, but that might not be easy or efficient to
implement.

-Stuart Sierra

Timothy Pratley

unread,
Apr 27, 2009, 7:28:39 PM4/27/09
to Clojure
> How can I pass a static java function to another function?

There is also memfn:
(memfn name & args)
Macro
Expands into code that creates a fn that expects to be passed an
object and any args and calls the named instance method on the object
passing the args. Use when you want to treat a Java method as a first-
class fn.

Boris Mizhen

unread,
Apr 27, 2009, 10:04:53 PM4/27/09
to Clojure
Thanks to all who replied.

To summarize what I learned - Clojure has a special form (. ) to
*call* java functions, but does not have concept of a *value*
corresponding to a java function.
This makes Java functions a second class citizen :)

In addition special forms are expanded in the first position of the
list, but not on other positions, thus in (foo Math/abs) Math/abs is
no longer a syntax for a static method, but a lookup of a var 'abs' in
a namespace Math.

Correct?

Regards,
Boris

Rich Hickey

unread,
Apr 28, 2009, 7:05:58 AM4/28/09
to Clojure


On Apr 27, 10:04 pm, Boris Mizhen <bo...@boriska.com> wrote:
> Thanks to all who replied.
>
> To summarize what I learned - Clojure has a special form (. ) to
> *call* java functions, but does not have concept of a *value*
> corresponding to a java function.
> This makes Java functions a second class citizen :)
>

Java was born a second-class citizen, Clojure doesn't make it so. In
particular, Java doesn't have proper functions, it has methods. They
are not first class values in Java, and Clojure can't fix that. You
can't pass Java methods by value and you can't apply them. While it
would be possible to automatically generate wrapper fns for Java
methods that would let you *pretend* they were functions, Clojure
currently doesn't do that, since doing so would often mean silently
generating code that uses reflection, and by the time you add
sufficient syntax to allow type hints, there's little benefit over #
().

> In addition special forms are expanded in the first position of the
> list, but not on other positions, thus in (foo Math/abs) Math/abs is
> no longer a syntax for a static method, but a lookup of a var 'abs' in
> a namespace Math.

>
> Correct?
>

What's correct is what is documented here:

http://clojure.org/java_interop

Rich

Rich Hickey

unread,
Apr 28, 2009, 7:23:06 AM4/28/09
to Clojure
Yes, areduce would be nicer if it looked like a binding set:

(areduce [aname anarray, ret init] expr)
(areduce [aname anarray, ret init, start-idx start-n] expr)
(areduce [aname anarray, ret init, start-idx start-n, end-idx end-n]
expr)

Treating amap similarly is slightly different since you don't supply
an initial value for ret.

You can put up an issue for this if you like.

Rich

Boris Mizhen

unread,
Apr 28, 2009, 10:58:02 AM4/28/09
to Clojure
Thanks Rich,

> What's correct is what is documented here: http://clojure.org/java_interop
RTFM is still very relevant :)

Boris
Reply all
Reply to author
Forward
0 new messages