<div dir="ltr"><div>Hi Vibhu,</div><div><br></div><div>I think our emails crossed. Fortunately I don't have to ask the list each time :-)</div><div>I have a successful POC using the functions I defined in my last email and one more.</div><div><br></div>(defun java-lambda-interface (class-or-object methodname position fn)<br> (let ((classname<br> (cond ((symbolp class-or-object) class-or-object)<br> ((jinstance-of-p class-or-object (find-java-class 'class)) (#"getName" class-or-object))<br> (t (#"getName" (jobject-class class-or-object))))))<br> (uiop/utility:call-with-muffled-conditions ;; so we don't get warnings about stubs <br> (lambda()<br> (destructuring-bind (interface methodname)<br> (java-lambda-parameter-information classname methodname position)<br> (jinterface-implementation interface methodname fn)))<br><div> '(simple-condition))))</div><div><br></div><div>I can then use this to create the interface and pass it where a lambda is being used as such:</div><div><br></div>(let ((jlambda (java-lambda-interface doc "forEachImageSegment" 0 #'print)))<br> (#"forEachImageSegment" doc jlambda))<div><br></div><div>and it works.<br></div><div><br></div><div>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.</div><div><br></div><div>Thanks to you both!</div><div>Alan</div><div><br></div><div><br></div><div><br></div></div><br><div class="gmail_quote"><div dir="ltr" class="gmail_attr">On Thu, Aug 25, 2022 at 10:19 AM Vibhu Mohindra <<a href="mailto:vibhu.mohindra@gmail.com" target="_blank">vibhu.mohindra@gmail.com</a>> wrote:<br></div><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Hi Alan,<br>
<br>
On 25/08/2022 06:36, Alan Ruttenberg wrote:<br>
> So in order to implement this I need to know the interface to use for <br>
> the lambda? Presumably I can determine this with reflection.<br>
<br>
You learn this not by reflection but by reading the library's source <br>
code, which you've done below to determine that the interface is <br>
Consumer not Function.<br>
<br>
> An example of one of the functions that takes the lambda is defined:<br>
> <br>
> public final NitfSegmentsFlow forEachImageSegment(final <br>
> Consumer<ImageSegment> consumer)<br>
> <br>
> But consumer has two methods: accept and andThen<br>
<br>
As Alessio said andThen() has a default implementation in Consumer (just <br>
as it did in Function).<br>
<br>
> Eventually it looks like accept is called on the consumer.<br>
<br>
That sounds right.<br>
<br>
> So in this <br>
> case it looks like I need to use jinterface-implementation and define <br>
> the accept method, no lambda necessary?<br>
<br>
You need to implement an accept() method somehow. One way is similar to <br>
how I'd shown an implementation of java.util.function.Function.apply(). <br>
(At the time I didn't know what type of object your library wanted so I <br>
assumed for concreteness that it was Function. Now we know it's <br>
Consumer. The principle of the technique I showed still applies.)<br>
<br>
I showed how to implement an adaptor class in Java. I noted that you <br>
could probably do the equivalent from ABCL. Alessio pointed out that <br>
that way was to use jinterface-implementation. So you don't _need_ to <br>
use a jinterface-implementation approach, but you can.<br>
<br>
You're right, it doesn't seem like you need to think about Java lambdas, <br>
just a Java interface (Consumer) and getting a new class that implements <br>
that interface and instantiating it to get an object. Whether you write <br>
that class in Java or by using jinterface-implementation in ABCL is a <br>
different matter.<br>
<br>
> What confuses me now is if a lambda is passed as the test code I'm <br>
> reading does:<br>
> <br>
> forEachImageSegment(imageSegment -> {do something})<br>
> <br>
> How does java know that the lambda is the implementation of accept <br>
> rather than andThen.<br>
<br>
As Alessio described, Java can only know this if an interface has a <br>
single (abstract) method in it. It then assumes that the lambda <br>
represents an implementation of that single method. You can see from the <br>
javadoc for Consumer that though it has more than one method, all but <br>
accept() have a "default" next to them, which means that the Consumer <br>
interface already provides a concrete implementation of them. That is, <br>
they aren't abstract. accept() doesn't have a "default" next to it, so <br>
it's abstract, meaning all concrete classes that claim to implement the <br>
interface must provide a concrete implementation of (at least) accept().<br>
<br>
> Or more practically, how do I figure out which <br>
> method to implement without reading the source code?<br>
<br>
1. By reading the javadoc for Consumer. I showed you an example for <br>
Function, which specifies a number of methods but only one (apply()) was <br>
abstract.<br>
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/8/docs/api/java/util/function/Function.html</a><br>
<a href="https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html" rel="noreferrer" target="_blank">https://docs.oracle.com/javase/8/docs/api/java/util/function/Consumer.html</a><br>
<br>
2. By asking on this list apparently :-) The answer is accept().<br>
<br>
----<br>
If you want to take a small step first, modify what I sent you earlier <br>
to work with Consumer instead of Function. The modification should be <br>
trivial. Once you've got that working, and if you don't like that the <br>
adaptor is written in Java or like experimenting, then explore the <br>
jinterface-implementation approach to do everything directly from ABCL.<br>
<br>
<br>
-- <br>
Vibhu<br>
<br>
</blockquote></div>