Re: Constructing a java lambda expression?
Alessio Stalla <[email protected]> Thu, 25 Aug 2022 12:35:17 +0200
| Newsgroups | gmane.editors.j.devel |
|---|---|
| Message-ID | <CAL2Kp+gFL3hG-MEO8aOjR_EdiTACOCTsoi1=xc-TLU3qvg0DGA@mail.gmail.com> |
--0000000000001ebf5005e70e5caa Content-Type: text/plain; charset="UTF-8" Because *andThen *is a *default method *in the interface, i.e. it's not abstract: https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html So, effectively, the interface only has one abstract method, and that's the target of lambda conversion. Now I have no idea if and how ABCL deals with default methods. If it's still stuck on Java 5/6 compatibility then I suspect that it can't, at least not in its Java code. On Thu, 25 Aug 2022 at 06:37, Alan Ruttenberg <[email protected]> wrote: > 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 >>> >>> --0000000000001ebf5005e70e5caa Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr"><div>Because <i>andThen </i>is a <b>default method </b>in = the interface, i.e. it's not abstract: <a href=3D"https://docs.oracle.c= om/javase/8/docs/api/java/util/function/Consumer.html">https://docs.oracle.= com/javase/8/docs/api/java/util/function/Consumer.html</a></div><div>So, ef= fectively, the interface only has one abstract method, and that's the t= arget of lambda conversion.</div><div>Now I have no idea if and how ABCL de= als with default methods. If it's still stuck on Java 5/6 compatibility= then I suspect that it can't, at least not in its Java code.<br></div>= </div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">= On Thu, 25 Aug 2022 at 06:37, Alan Ruttenberg <<a href=3D"mailto:alanrut= [email protected]">[email protected]</a>> wrote:<br></div><blockq= uote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-left:1p= x solid rgb(204,204,204);padding-left:1ex"><div dir=3D"ltr"><div>So in orde= r to implement this I need to know the interface to use for the lambda? Pre= sumably I can determine this with reflection.<br></div><div><br></div><div>= An example of one of the functions that takes the lambda is defined:</div><= div><br></div><div>public final NitfSegmentsFlow forEachImageSegment(final = Consumer<ImageSegment> consumer) <br></div><div><br></div><div>But co= nsumer has two methods: accept and andThen <br></div><div><br></div><div>Ev= entually 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 m= ethod, no lambda necessary?</div><div><br></div><div>What confuses me now i= s if a lambda is passed as the test code I'm reading does:</div><div><b= r></div><div>forEachImageSegment(imageSegment -> {do something})</div><d= iv><br></div><div>How does java know that the lambda is the implementation = of accept rather than andThen. Or more practically, how do I figure out whi= ch 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 cla= ss=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr">On Wed, Aug 24, 20= 22 at 4:14 AM Alessio Stalla <<a href=3D"mailto:[email protected]"= target=3D"_blank">[email protected]</a>> wrote:<br></div><blockqu= ote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;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 interface does not e= xist. But any Java interface with a single abstract method can be the targe= t of a lambda expression:</div><div><pre style=3D"background-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-weight:bold;font-st= yle:italic">out</span>.println(<span style=3D"color:rgb(0,128,0);font-weigh= t:bold">"foo"</span>); }).run();</pre></div><div>The Thread const= ructor takes a Runnable argument, not a Function.</div><div><br></div><div>= Lambda is just syntax sugar for interfaces with a single method, so you can= reproduce them on ABCL with the jinterface thing + some macrology.<br></di= v></div><br><div class=3D"gmail_quote"><div dir=3D"ltr" class=3D"gmail_attr= ">On Wed, 24 Aug 2022 at 05:10, Vibhu Mohindra <<a href=3D"mailto:vibhu.= [email protected]" target=3D"_blank">[email protected]</a>> wrot= e:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0= .8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">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> </blockquote></div> --0000000000001ebf5005e70e5caa--