groovy-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Jochen Theodorou <blackd...@gmx.org>
Subject Re: JDK8 Streams / Closure cast to interface
Date Wed, 23 Nov 2016 10:11:05 GMT


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

Mime
View raw message