On 22.11.2016 19:37, Winnebeck, Jason wrote:
I was referring to a compile-time generation of the class -- that the Closure 
itself that is normally generated implements the interface natively.

Which means we are talking about direct assignments to local variables only? I mean the static compiler can do that in more cases, but frankly, why should the static compiler even bother with creating a Closure?

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?

Android is ok, yes. As efficient as Java without lambdas... well.. that I am not sure of. Even if you make it as an anonymous inner class that implements the interface and extends Closure, even if the interface method will just call doCall, you will still have to pay the initialization cost of the Closure, and Closure will inspect itself to set the maximum parameter number for example, you will still request a meta class and do some other things. So the init would not be as efficient. The method invocation should be similar to Java, if done from Java then, since there is no dynamic call. So here you would gain over todays Closure.

But for typical usages of non-static Groovy the gain would be almost nil. Unless we can lift restrictions

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?

It depends on if the implicit "this" is used or not. { println it } uses implicit this, thus cannot do it for sure. { this.println it }, no implicit, thus can be optimized.

I am wondering what would happen if we had 2 versions, one with implicit this delegation logic, the other not. Because if the usage is just an appended block and the target is just a functional interface, you will not need the version with delegate.

bye Jochen

Reply via email to