Re: Constructing a java lambda expression?
Alan Ruttenberg <[email protected]> Thu, 25 Aug 2022 00:36:33 -0400
| Newsgroups | gmane.editors.j.devel |
|---|---|
| Message-ID | <CAFKQJ8m3dEJPM2tF7efSta3z_RzA=22D8t=2cpFcnmHDqC-V5Q@mail.gmail.com> |
--000000000000337dd905e709591a
Content-Type: text/plain; charset="UTF-8"
So in order to implement this I need to know the interface to use for the
lambda? Presumably I can determine this with reflection.
An example of one of the functions that takes the lambda is defined:
public final NitfSegmentsFlow forEachImageSegment(final
Consumer<ImageSegment> consumer)
But consumer has two methods: accept and andThen
Eventually it looks like accept is called on the consumer. So in this case
it looks like I need to use jinterface-implementation and define the accept
method, no lambda necessary?
What confuses me now is if a lambda is passed as the test code I'm reading
does:
forEachImageSegment(imageSegment -> {do something})
How does java know that the lambda is the implementation of accept rather
than andThen. Or more practically, how do I figure out which method to
implement without reading the source code?
Thanks,
Alan
On Wed, Aug 24, 2022 at 4:14 AM Alessio Stalla <[email protected]>
wrote:
> Function is a convenient interface for cases when a more specific
> interface does not exist. But any Java interface with a single abstract
> method can be the target of a lambda expression:
>
> new Thread(() -> { System.out.println("foo"); }).run();
>
> The Thread constructor takes a Runnable argument, not a Function.
>
> Lambda is just syntax sugar for interfaces with a single method, so you
> can reproduce them on ABCL with the jinterface thing + some macrology.
>
> On Wed, 24 Aug 2022 at 05:10, Vibhu Mohindra <[email protected]>
> wrote:
>
>> On 23/08/2022 05:27, Alan Ruttenberg wrote:
>> > There's a library I want to use that takes a lambda as an argument.
>> > Anyone know how to construct one in ABCL?
>>
>> I assume it's a Java library taking a Java Lambda that you want to call
>> from ABCL.
>>
>> A Java Lambda is really an instance of one of the classes in
>> java.util.function. Which one depends on how many parameters it has and
>> whether it returns a value. Let's assume your library wants a Java
>> Lambda that has one parameter and returns a value. That's a
>> java.util.function.Function. Say it looks like this:
>>
>> //Lib.java
>> public class Lib {
>> public static void f(java.util.function.Function f) {
>> System.out.println("You answered: " + f.apply(5));
>> }
>> }
>>
>> such that it can be used from Java with a Java Lambda like this:
>>
>> Lib.f((Object x) -> (Integer)x * (Integer)x);
>> => You answered: 25
>>
>> You'd like to give it a Lisp Lambda from ABCL as follows:
>>
>> (jstatic "f" "Lib" #'(lambda (x) (* x x)))
>>
>> but that's not allowed because although Java can implicitly convert from
>> a Java Lambda to a java.util.function.Function, it can't convert from a
>> Lisp Lambda to a java.util.function.Function.
>>
>> A Lisp Lambda is really an org.armedbear.lisp.Function. So one solution
>> is to adapt that.
>>
>> //Adaptor.java
>> import org.armedbear.lisp.*;
>> public class Adaptor implements java.util.function.Function {
>> private org.armedbear.lisp.Function lispFn;
>> public Adaptor(org.armedbear.lisp.Function lispFunction) {
>> this.lispFn = lispFunction;
>> }
>> public Object apply(Object input) {
>> return lispFn.execute(
>> JavaObject.getInstance(input, true)).javaInstance();
>> }
>> }
>>
>> and use it from ABCL like this:
>>
>> (jstatic "f" "Lib" (jnew "Adaptor" #'(lambda (x) (* x x))))
>> => You answered: 25
>> => NIL
>>
>> ----
>> Notes:
>>
>> I'm on Java 10, ABCL-1.4.0 (which is old).
>> I did this to build and run, starting with the jar and two java files in
>> the current directory:
>> javac -classpath abcl-1.4.0.jar:. Adaptor.java Lib.java
>> java -classpath abcl-1.4.0.jar:. org.armedbear.lisp.Main
>> > (jstatic "f" "Lib" (jnew "Adaptor" #'(lambda (x) (* x x))))
>>
>> You can probably create the Adaptor class from within ABCL if you don't
>> like that it's written in Java, but I don't remember how to. ABCL's
>> documentation might describe such bytecode generation somewhere.
>>
>> Pointers:
>> Java: java.util.function.*
>> ABCL: In org.armedbear.lisp, LispObject, JavaObject, Function
>>
>>
>> --
>> Vibhu
>>
>>
--000000000000337dd905e709591a
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable
<div dir=3D"ltr"><div>So in order to implement this I need to know the inte=
rface to use for the lambda? Presumably I can determine this with reflectio=
n.<br></div><div><br></div><div>An example of one of the functions that tak=
es the lambda is defined:</div><div><br></div><div>public final NitfSegment=
sFlow forEachImageSegment(final Consumer<ImageSegment> consumer) <br>=
</div><div><br></div><div>But consumer has two methods: accept and andThen =
<br></div><div><br></div><div>Eventually it looks like accept is called on =
the consumer. So in this case it looks like I need to use jinterface-implem=
entation and define the accept method, no lambda necessary?</div><div><br><=
/div><div>What confuses me now is if a lambda is passed as the test code I&=
#39;m reading does:</div><div><br></div><div>forEachImageSegment(imageSegme=
nt -> {do something})</div><div><br></div><div>How does java know that t=
he lambda is the implementation of accept rather than andThen. Or more prac=
tically, how do I figure out which method to implement without reading the =
source code?<br></div><div><br></div><div>Thanks,<br></div><div>Alan</div><=
div><br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=
=3D"gmail_attr">On Wed, Aug 24, 2022 at 4:14 AM Alessio Stalla <<a href=
=3D"mailto:[email protected]">[email protected]</a>> wrote:<=
br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8e=
x;border-left:1px solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"=
><div>Function is a convenient interface for cases when a more specific int=
erface does not exist. But any Java interface with a single abstract method=
can be the target of a lambda expression:</div><div><pre style=3D"backgrou=
nd-color:rgb(255,255,255);color:rgb(0,0,0);font-family:"JetBrains Mono=
",monospace"><span style=3D"color:rgb(0,0,128);font-weight:bold">new <=
/span>Thread(() -> { System.<span style=3D"color:rgb(102,14,122);font-we=
ight:bold;font-style:italic">out</span>.println(<span style=3D"color:rgb(0,=
128,0);font-weight:bold">"foo"</span>); }).run();</pre></div><div=
>The Thread constructor takes a Runnable argument, not a Function.</div><di=
v><br></div><div>Lambda is just syntax sugar for interfaces with a single m=
ethod, so you can reproduce them on ABCL with the jinterface thing + some m=
acrology.<br></div></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" cl=
ass=3D"gmail_attr">On Wed, 24 Aug 2022 at 05:10, Vibhu Mohindra <<a href=
=3D"mailto:[email protected]" target=3D"_blank">vibhu.mohindra@gmail=
.com</a>> wrote:<br></div><blockquote class=3D"gmail_quote" style=3D"mar=
gin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1=
ex">On 23/08/2022 05:27, Alan Ruttenberg wrote:<br>
> There's a library I want to use that takes a lambda as an argument=
. <br>
> Anyone know how to construct one in ABCL?<br>
<br>
I assume it's a Java library taking a Java Lambda that you want to call=
<br>
from ABCL.<br>
<br>
A Java Lambda is really an instance of one of the classes in <br>
java.util.function. Which one depends on how many parameters it has and <br=
>
whether it returns a value. Let's assume your library wants a Java <br>
Lambda that has one parameter and returns a value. That's a <br>
java.util.function.Function. Say it looks like this:<br>
<br>
//Lib.java<br>
public class Lib {<br>
=C2=A0 =C2=A0public static void f(java.util.function.Function f) {<br>
=C2=A0 =C2=A0 =C2=A0System.out.println("You answered: " + f.apply=
(5));<br>
=C2=A0 =C2=A0}<br>
}<br>
<br>
such that it can be used from Java with a Java Lambda like this:<br>
<br>
Lib.f((Object x) -> (Integer)x * (Integer)x);<br>
=3D> You answered: 25<br>
<br>
You'd like to give it a Lisp Lambda from ABCL as follows:<br>
<br>
(jstatic "f" "Lib" #'(lambda (x) (* x x)))<br>
<br>
but that's not allowed because although Java can implicitly convert fro=
m <br>
a Java Lambda to a java.util.function.Function, it can't convert from a=
<br>
Lisp Lambda to a java.util.function.Function.<br>
<br>
A Lisp Lambda is really an org.armedbear.lisp.Function. So one solution <br=
>
is to adapt that.<br>
<br>
//Adaptor.java<br>
import org.armedbear.lisp.*;<br>
public class Adaptor implements java.util.function.Function {<br>
=C2=A0 =C2=A0private org.armedbear.lisp.Function lispFn;<br>
=C2=A0 =C2=A0public Adaptor(org.armedbear.lisp.Function lispFunction) {<br>
=C2=A0 =C2=A0 =C2=A0this.lispFn =3D lispFunction;<br>
=C2=A0 =C2=A0}<br>
=C2=A0 =C2=A0public Object apply(Object input) {<br>
=C2=A0 =C2=A0 =C2=A0return lispFn.execute(<br>
=C2=A0 =C2=A0 =C2=A0 =C2=A0JavaObject.getInstance(input, true)).javaInstanc=
e();<br>
=C2=A0 =C2=A0}<br>
}<br>
<br>
and use it from ABCL like this:<br>
<br>
(jstatic "f" "Lib" (jnew "Adaptor" #'(lam=
bda (x) (* x x))))<br>
=3D> You answered: 25<br>
=3D> NIL<br>
<br>
----<br>
Notes:<br>
<br>
I'm on Java 10, ABCL-1.4.0 (which is old).<br>
I did this to build and run, starting with the jar and two java files in <b=
r>
the current directory:<br>
javac -classpath abcl-1.4.0.jar:. Adaptor.java Lib.java<br>
java -classpath abcl-1.4.0.jar:. org.armedbear.lisp.Main<br>
=C2=A0> (jstatic "f" "Lib" (jnew "Adaptor"=
#'(lambda (x) (* x x))))<br>
<br>
You can probably create the Adaptor class from within ABCL if you don't=
<br>
like that it's written in Java, but I don't remember how to. ABCL&#=
39;s <br>
documentation might describe such bytecode generation somewhere.<br>
<br>
Pointers:<br>
Java: java.util.function.*<br>
ABCL: In org.armedbear.lisp, LispObject, JavaObject, Function<br>
<br>
<br>
-- <br>
Vibhu<br>
<br>
</blockquote></div>
</blockquote></div>
--000000000000337dd905e709591a--