I was referring to a compile-time generation of the class -- that the Closure 
itself that is normally generated implements the interface natively. That would 
make it equivalent to anonymous class in Java 7 and earlier for calling 
functional (or any SAM type) methods. That wouldn't have any problems on 
Android, and should be as efficient as Java without lambdas? I would assume the 
interface's method delegating to doCall would get inlined. In other words, 
Groovy generating code like:

class X {
        public static void main(String[] args) {
                Stream.of(1).forEach(new x__closure1(X.class, X.class));
        }

        private static class x__closure1 extends Closure<Void> implements 
Consumer<Integer> {
                public x__closure1(Object owner, Object thisObject) {
                        super(owner, thisObject);
                }

                void doCall(Integer x) {
                        System.out.println(x);
                }

                @Override
                public void accept(Integer x) {
                        doCall(x);
                }
        }
}

>From Groovy: Stream.of(1).forEach { println it }

The new part being that Groovy added the accept method and implements to the 
closure it already normally would have generated, and castToType would not need 
to be called. All of the code manipulation is done at compile-time so it is 
fully STC and Android compatible, and no reflection is in use. You still have 
the a little more overhead of Closure object compared to Java static inner 
class, but I imagine this must be a lot less than proxy, but still allows 
Closure to use the owner/delegate patterns that Groovy is known for, and I 
assume would not affect backwards compatibility as superclass stays Closure.

Of course, if it were possible for compiler to determine that the closure is 
never using owner, delegate, or "thisObject", then it could be possible to drop 
the "extends Closure" entirely if it can be proven that the "closureness" of 
the object can never be observed. But that's likely not possible as any method 
taking an interface could choose to check for instanceof Closure and/or cast or 
do something special if Groovy closure is passed in -- although is that even 
possible today since Groovy actually passes in a proxy?

Jason

-----Original Message-----
From: Jochen Theodorou [mailto:[email protected]] 
Sent: Tuesday, November 22, 2016 12:01 PM
To: [email protected]
Subject: Re: JDK8 Streams / Closure cast to interface



On 22.11.2016 15:14, Winnebeck, Jason wrote:
> I love Groovy. I also love the new streams functionality in JDK 8. 
> But, I am weary of the performance implications of Groovy + Streams, 
> because to use streams you must use Groovy closures. I see the code 
> generated creates a new closure instance then uses castToType to cast 
> the closure to the JDK8 functionality interface. Does Groovy make this 
> efficient, or is the proxy generation from this going to be excessive 
> if running a lot of small stream operations?

it is using a dynamic proxy with some optimized code paths.. such a proxy does 
for example not have to go through call to get to doCall. If you want this 
really efficient, you have to skip the generation of the Groovy Closure 
instance. This is doable and I plan to do this, but it will be a breaking 
change (all open blocks would be realized using the same class for example, 
having that instance would even become optional).

> I think an interesting feature of Groovy would be if it sees a closure 
> cast implicitly or explicitly to a certain interface type, it could 
> make the closure implement the interface.  You'd still have the 
> overhead of compile-time class generation versus lambdas, but at least 
> you wouldn't have to create proxies, and maybe there is an improved 
> chance of JIT inlining? Even if it was supported within a single 
> statement, like "Function<String, String> x = {it.trim()}" or 
> Stream.of("abc").map {
> it.trim() }, the closure with trim could implement Function. Of course 
> for backwards compatibility the class could still extend Closure and 
> still implement call methods, but also implement the method apply, 
> which delegates to call.

The price question is now... is that going to be cheaper? runtime class 
generation is much more expensive than a reflective call - and considering 
Android, also much more problematic. And you have to be aware of the 
following... If I make a method call with an open block to a method taking a 
functional interface, the point in time for the conversion is after runtime 
method selection and before the actual invocation (or during invocation). At 
this point the original Closure instance already exists. Really, without test 
it is difficult to tell about the gain here

Real gains you get only with a much deeper integration

bye Jochen

This email message and any attachments are for the sole use of the intended 
recipient(s). Any unauthorized review, use, disclosure or distribution is 
prohibited. If you are not the intended recipient, please contact the sender by 
reply email and destroy all copies of the original message and any attachments.

Reply via email to