Constructing a java lambda expression?

Alan Ruttenberg alanruttenberg at gmail.com
Thu Aug 25 17:57:39 UTC 2022


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 <vibhu.mohindra at gmail.com>
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<ImageSegment> 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: <https://mailman.common-lisp.net/pipermail/armedbear-devel/attachments/20220825/76b29dd6/attachment-0001.html>


More information about the armedbear-devel mailing list