From rpgoldman at sift.info Sun Aug 7 22:43:22 2022 From: rpgoldman at sift.info (Robert Goldman) Date: Sun, 07 Aug 2022 17:43:22 -0500 Subject: ASDF 3.3.6 is released Message-ID: <52A73B8C-717E-4B53-88BC-4DBA9EDCBD66@sift.info> Dear Lisp Implementation Developers and Maintainers, Today we release ASDF 3.3.6, the sixth bugfix release for the 3.3 release series, and -- it is devoutly to be hoped -- the final one. We urge implementations that are currently bundling previous versions of ASDF -- and especially those bundling 3.3.0 through 3.3.5 -- to upgrade to 3.3.6 at their earliest convenience. As maintainer, my primary role continues to be coordination and some limited quality control. The real work for this release has been done by many contributors and bug-reporters, to whom the Common Lisp community owes a tremendous vote of thanks. Their names are listed on the Changelog, appended below. An extra special thanks is due to my co-maintainer, Eric Timmons, who has provided many fixes and also has overhauled and much improved our regression testing. We *hope* that the next release will be 3.4, introducing new functionality but which, as the numbering suggests, will be backward compatible. Best, Robert * Fix bug loading ASDF system definitions from jar files on ABCL. See !190 * Fix bug with version numbering after reload. See !194 and #94. Thanks to Eric Timmons. * Fix bug in return value of UPGRADE-ASDF. See !195. Again, thanks to Eric Timmons. * Multiple improvements to documentation and tests. Thanks to Nathan Ringo and Phoebe Goldman. * Add clasp support for uiop/launch program. Thanks to Christian Schafmeister. * Miscellaneous minor bug fixes and tweaks. * Don't let *package* binding leak into ASDF compile operations. Thanks to Phoebe Goldman. -------------- next part -------------- An HTML attachment was scrubbed... URL: From alanruttenberg at gmail.com Tue Aug 23 03:27:50 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Mon, 22 Aug 2022 23:27:50 -0400 Subject: Constructing a java lambda expression? Message-ID: There's a library I want to use that takes a lambda as an argument. Anyone know how to construct one in ABCL? Thanks, Alan -------------- next part -------------- An HTML attachment was scrubbed... URL: From alessiostalla at gmail.com Tue Aug 23 08:46:48 2022 From: alessiostalla at gmail.com (Alessio Stalla) Date: Tue, 23 Aug 2022 10:46:48 +0200 Subject: Constructing a java lambda expression? In-Reply-To: References: Message-ID: A lambda is just an interface implementation. On Tue, 23 Aug 2022 at 05:40, 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? > > Thanks, > Alan > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alanruttenberg at gmail.com Tue Aug 23 18:43:21 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Tue, 23 Aug 2022 14:43:21 -0400 Subject: Constructing a java lambda expression? In-Reply-To: References: Message-ID: Hi Alessio, Thanks for the response. Could you give me a little more to go on? Perhaps a pointer to a page that shows how to substitute an interface where a lambda occurs in an argument list? Best, Alan On Tue, Aug 23, 2022 at 4:47 AM Alessio Stalla wrote: > A lambda is just an interface implementation. > > On Tue, 23 Aug 2022 at 05:40, 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? >> >> Thanks, >> Alan >> > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vibhu.mohindra at gmail.com Wed Aug 24 02:58:50 2022 From: vibhu.mohindra at gmail.com (Vibhu Mohindra) Date: Wed, 24 Aug 2022 04:58:50 +0200 Subject: Constructing a java lambda expression? In-Reply-To: References: Message-ID: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> 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 From alessiostalla at gmail.com Wed Aug 24 07:42:59 2022 From: alessiostalla at gmail.com (Alessio Stalla) Date: Wed, 24 Aug 2022 09:42:59 +0200 Subject: Constructing a java lambda expression? In-Reply-To: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: 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 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 > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From vibhu.mohindra at gmail.com Wed Aug 24 12:23:15 2022 From: vibhu.mohindra at gmail.com (Vibhu Mohindra) Date: Wed, 24 Aug 2022 14:23:15 +0200 Subject: Constructing a java lambda expression? In-Reply-To: References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: <2488fa7e-a3d6-007a-866b-89be1ad90917@gmail.com> On 24/08/2022 09:42, Alessio Stalla 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: > > [...] > Lambda is just syntax sugar for interfaces with a single method, [...]. You're absolutely right. I'd forgotten all this. Vibhu From alanruttenberg at gmail.com Wed Aug 24 16:11:17 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Wed, 24 Aug 2022 12:11:17 -0400 Subject: Constructing a java lambda expression? In-Reply-To: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: This is exactly what I was looking for! I'll give it a try and then see about integrating something like this into jss. Thanks so much, Alan On Tue, Aug 23, 2022 at 11:10 PM Vibhu Mohindra 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 > > -------------- next part -------------- An HTML attachment was scrubbed... URL: From alanruttenberg at gmail.com Thu Aug 25 04:36:33 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Thu, 25 Aug 2022 00:36:33 -0400 Subject: Constructing a java lambda expression? In-Reply-To: References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: 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 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 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 > 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 >> >> -------------- next part -------------- An HTML attachment was scrubbed... URL: From alessiostalla at gmail.com Thu Aug 25 10:35:17 2022 From: alessiostalla at gmail.com (Alessio Stalla) Date: Thu, 25 Aug 2022 12:35:17 +0200 Subject: Constructing a java lambda expression? In-Reply-To: References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: 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 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 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 > 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 >> 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 >>> >>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From alanruttenberg at gmail.com Thu Aug 25 14:13:31 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Thu, 25 Aug 2022 10:13:31 -0400 Subject: Constructing a java lambda expression? In-Reply-To: References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: Thanks. (defun get-abstract-methods (classname) (map 'list #"getName" (remove-if-not (lambda(x) (let ((modifiers (#"getModifiers" x))) (and (#"isAbstract" 'reflect.Modifier modifiers) (not (#"isStatic" 'reflect.Modifier modifiers))))) (#"getDeclaredMethods" (find-java-class classname))))) (defun java-lambda-parameter-information (classname methodname position) (let* ((method (find methodname (#"getDeclaredMethods" (find-java-class classname)) :key #"getName" :test 'equalp)) (parameter-type (elt (#"getParameterTypes" method) position)) (abstract-methods (get-abstract-methods parameter-type))) (assert (#"isInterface" parameter-type) () "lambda parameter type ~a should be an interface but isn't" (#"getName" parameter-type)) (assert (= (length abstract-methods) 1) () "Parameter ~a type ~a has more than one abstract method: ~{~a~^, ~}" position (#"getName" parameter-type) abstract-methods) (list (#"getName" parameter-type) (car abstract-methods)))) (java-lambda-parameter-information 'Nitfsegmentsflowimpl "forEachImagesegment" 0) -> ("java.util.function.Consumer" "accept") Cheers, Alan On Thu, Aug 25, 2022 at 6:35 AM Alessio Stalla wrote: > 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 > 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 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 >> 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 >>> 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 >>>> >>>> -------------- next part -------------- An HTML attachment was scrubbed... URL: From vibhu.mohindra at gmail.com Thu Aug 25 14:18:44 2022 From: vibhu.mohindra at gmail.com (Vibhu Mohindra) Date: Thu, 25 Aug 2022 16:18:44 +0200 Subject: Constructing a java lambda expression? In-Reply-To: References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> Message-ID: <67e8d8ee-1b48-c309-5816-64b813424cb9@gmail.com> Hi Alan, On 25/08/2022 06:36, Alan Ruttenberg 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. You learn this not by reflection but by reading the library's source code, which you've done below to determine that the interface is Consumer not Function. > An example of one of the functions that takes the lambda is defined: > > public final NitfSegmentsFlow forEachImageSegment(final > Consumer consumer) > > But consumer has two methods: accept and andThen As Alessio said andThen() has a default implementation in Consumer (just as it did in Function). > Eventually it looks like accept is called on the consumer. That sounds right. > So in this > case it looks like I need to use jinterface-implementation and define > the accept method, no lambda necessary? You need to implement an accept() method somehow. One way is similar to how I'd shown an implementation of java.util.function.Function.apply(). (At the time I didn't know what type of object your library wanted so I assumed for concreteness that it was Function. Now we know it's Consumer. The principle of the technique I showed still applies.) I showed how to implement an adaptor class in Java. I noted that you could probably do the equivalent from ABCL. Alessio pointed out that that way was to use jinterface-implementation. So you don't _need_ to use a jinterface-implementation approach, but you can. You're right, it doesn't seem like you need to think about Java lambdas, just a Java interface (Consumer) and getting a new class that implements that interface and instantiating it to get an object. Whether you write that class in Java or by using jinterface-implementation in ABCL is a different matter. > 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. As Alessio described, Java can only know this if an interface has a single (abstract) method in it. It then assumes that the lambda represents an implementation of that single method. You can see from the javadoc for Consumer that though it has more than one method, all but accept() have a "default" next to them, which means that the Consumer interface already provides a concrete implementation of them. That is, they aren't abstract. accept() doesn't have a "default" next to it, so it's abstract, meaning all concrete classes that claim to implement the interface must provide a concrete implementation of (at least) accept(). > Or more practically, how do I figure out which > method to implement without reading the source code? 1. By reading the javadoc for Consumer. I showed you an example for Function, which specifies a number of methods but only one (apply()) was abstract. https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html 2. By asking on this list apparently :-) The answer is accept(). ---- If you want to take a small step first, modify what I sent you earlier to work with Consumer instead of Function. The modification should be trivial. Once you've got that working, and if you don't like that the adaptor is written in Java or like experimenting, then explore the jinterface-implementation approach to do everything directly from ABCL. -- Vibhu From alanruttenberg at gmail.com Thu Aug 25 17:57:39 2022 From: alanruttenberg at gmail.com (Alan Ruttenberg) Date: Thu, 25 Aug 2022 13:57:39 -0400 Subject: Constructing a java lambda expression? In-Reply-To: <67e8d8ee-1b48-c309-5816-64b813424cb9@gmail.com> References: <4e2b3957-70a2-2703-5112-c7a6a5e24fe3@gmail.com> <67e8d8ee-1b48-c309-5816-64b813424cb9@gmail.com> Message-ID: Hi Vibhu, I think our emails crossed. Fortunately I don't have to ask the list each time :-) I have a successful POC using the functions I defined in my last email and one more. (defun java-lambda-interface (class-or-object methodname position fn) (let ((classname (cond ((symbolp class-or-object) class-or-object) ((jinstance-of-p class-or-object (find-java-class 'class)) (#"getName" class-or-object)) (t (#"getName" (jobject-class class-or-object)))))) (uiop/utility:call-with-muffled-conditions ;; so we don't get warnings about stubs (lambda() (destructuring-bind (interface methodname) (java-lambda-parameter-information classname methodname position) (jinterface-implementation interface methodname fn))) '(simple-condition)))) I can then use this to create the interface and pass it where a lambda is being used as such: (let ((jlambda (java-lambda-interface doc "forEachImageSegment" 0 #'print))) (#"forEachImageSegment" doc jlambda)) and it works. I'll do some work to integrate into jss and avoid doing all of this dynamically every time the lambda is used, where possible etc. Thanks to you both! Alan On Thu, Aug 25, 2022 at 10:19 AM Vibhu Mohindra wrote: > Hi Alan, > > On 25/08/2022 06:36, Alan Ruttenberg 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. > > You learn this not by reflection but by reading the library's source > code, which you've done below to determine that the interface is > Consumer not Function. > > > An example of one of the functions that takes the lambda is defined: > > > > public final NitfSegmentsFlow forEachImageSegment(final > > Consumer consumer) > > > > But consumer has two methods: accept and andThen > > As Alessio said andThen() has a default implementation in Consumer (just > as it did in Function). > > > Eventually it looks like accept is called on the consumer. > > That sounds right. > > > So in this > > case it looks like I need to use jinterface-implementation and define > > the accept method, no lambda necessary? > > You need to implement an accept() method somehow. One way is similar to > how I'd shown an implementation of java.util.function.Function.apply(). > (At the time I didn't know what type of object your library wanted so I > assumed for concreteness that it was Function. Now we know it's > Consumer. The principle of the technique I showed still applies.) > > I showed how to implement an adaptor class in Java. I noted that you > could probably do the equivalent from ABCL. Alessio pointed out that > that way was to use jinterface-implementation. So you don't _need_ to > use a jinterface-implementation approach, but you can. > > You're right, it doesn't seem like you need to think about Java lambdas, > just a Java interface (Consumer) and getting a new class that implements > that interface and instantiating it to get an object. Whether you write > that class in Java or by using jinterface-implementation in ABCL is a > different matter. > > > 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. > > As Alessio described, Java can only know this if an interface has a > single (abstract) method in it. It then assumes that the lambda > represents an implementation of that single method. You can see from the > javadoc for Consumer that though it has more than one method, all but > accept() have a "default" next to them, which means that the Consumer > interface already provides a concrete implementation of them. That is, > they aren't abstract. accept() doesn't have a "default" next to it, so > it's abstract, meaning all concrete classes that claim to implement the > interface must provide a concrete implementation of (at least) accept(). > > > Or more practically, how do I figure out which > > method to implement without reading the source code? > > 1. By reading the javadoc for Consumer. I showed you an example for > Function, which specifies a number of methods but only one (apply()) was > abstract. > https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html > https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html > > 2. By asking on this list apparently :-) The answer is accept(). > > ---- > If you want to take a small step first, modify what I sent you earlier > to work with Consumer instead of Function. The modification should be > trivial. Once you've got that working, and if you don't like that the > adaptor is written in Java or like experimenting, then explore the > jinterface-implementation approach to do everything directly from ABCL. > > > -- > Vibhu > > -------------- next part -------------- An HTML attachment was scrubbed... URL: