 |
Closure and performance
Posted by forax on August 24, 2006 at 05:09 AM | Comments (12)
I've read the proposal about
function types and closures
and i have noticed that the invocation
of a function type will use the newly introduced bytecode invokedynamic (the gilad blog about invokedynamic) and i think i know why !
So let me introduce a small example of closure, the method
transform applies a transformation
on each item of an array and store the result in the same array.
The transformation is specified using a
function type typed CharSequence(CharSequence)
i.e. a function that takes a CharSequence and returns a CharSequence.
static CharSequence[] transform(CharSequence(CharSequence) transformation,CharSequence... array) {
for(int i=0;i<array.length;i++) {
array[i]=transformation(array[i]);
}
return array;
}
The following code applies an identity transformation :
CharSequence(CharSequence) identity = (CharSequence seq) {return seq; };
CharSequence[] seqs=transform(identity,"2","3");
System.out.println(Arrays.toString(seqs));
So why closure can't use a classical call (invokevirtual)
instead of a invokedynamic call,
because the proposal defines subtyping rules between closures.
It is possible to use a function type with not exactly the same
type the the one defined. In our example, the declared signature
is CharSequence(CharSequence seq), one can use instead
a closure typed, by example, String(Object).
String(Object) bang = (Object o) {return "!"+o; };
CharSequence[] seqs2=transform(bang,"2","3");
System.out.println(Arrays.toString(seqs2));
So in the method transform, the call to
transformation can call
a function type with a different signature that the one declared,
that's why invokedynamic must be used here.
So why using invokedynamic is important, it's because it can
hurt performance, invoking a method without the same signature
is more complex than a simple call.
In C#, a delegate method call (a roughly equivalent to closure) is more
expensive than a method call.
Note that this is a special case of invokedynamic, there is
only one method that is applicable for a specific closure
so a smart VM can optimise this case.
Bookmark blog post: del.icio.us Digg DZone Furl Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment
-
I'm not so sure. We are already doing this kind of stuff in Java5 for generics (I think they are called bridge methods.) So one could conceivably implement it in the same way, without using invokedynamic. There might be other reasons why invokedynamic is needed for closure, but I don't think it's because of the reason you mentioned.
Posted by: kohsuke on August 24, 2006 at 10:56 AM
-
In case of bridge method, the compiler knows the signature of the overrided method, so it can generate an had-oc bridge,
in case of closure, the compiler doesn't know the exact signature of the function type that will call the closure.
The compiler can't generate given a signature all the possible bridges because the number of these bridges is exponential and the subtyping rules defined in the proposal permits to use contravariant parameter type so the signature can contain type not known at the closure creation (loaded by the VM after).
Posted by: forax on August 24, 2006 at 02:40 PM
-
On .NET Delegates: delegate calls are more expensive because they do more; a .NET Delegate has a list of method pointers, and when the Delegate is called it walks the list and calls each method pointer.
Posted by: murphee on August 25, 2006 at 10:06 AM
-
Must be the worst proposal ever to be added to the language. Just when you thought they couldn't make the syntax more obscure they find a way to do it anyway.
Almost makes me look longingly at Cobol again, but for now I can stick with a decent Java version like 1.4 or 5.0 instead of this nonsense (or the built-in SOAP servers and embedded database enbines of 6.0).
After this, all we need is operator overloading, getting rid of typed parameters completely, and true multiple inheritance, and we probably have every worst bit of every language in existence integrated into one tidy package.
Posted by: jwenting on August 25, 2006 at 11:39 AM
-
I wish the Java Goods would stop fucking up the language. Was the addition of generics not bad enough?No, they can't resist of thinking about yet another vanity feature. There are a thousand bug which needs to be fixed. They claimed they don't have enough resources to maintain such a simple thing like JavaComm for Windows, they couldn't get generics right, but they consider adding closures to the language.It is as if they have some inferiority complex. Some other languages have this, so they need to add a half backed version to Java.
Posted by: ewin on August 25, 2006 at 02:27 PM
-
All the compiler needs to generate is a bridge method that takes Objects and return an Object. The call to a function type can be done like an erasure. The arity of the function is fixed, so this simple strategy works.
So I still maintain that invokedynamic is not a must.
Posted by: kohsuke on August 25, 2006 at 09:31 PM
-
@murphee, i know, that is the difference between system.Delegate and system.MulticastDelegate.
@jwenting, embed derby in the JDK is a good Think(TM), it's fairly easy for a newbie to use JDBC now. I agree with you about the ruby-esque syntax of the proposal (i've read your blog about it) but closure is more important than that.
@ewin, if a bug bother you, why not fix it by yourself ?
@kohsuke, i see, it could work but i'm not sure that your solution will be better than using invokedynamic. Basically because the implementation of invokedynamic in this case will perform the same casts that your bridge.
Rémi Forax
Posted by: forax on August 26, 2006 at 05:45 AM
-
if a bug bother you, why not fix it by yourself ?
Is that all you have to say? Well, this kind of arrogance surely qualifies you to work for Sun.
I can't contribute any code to Java, because I can't sign the SCA. I would have to make a number of false statements when signing it. E.g. when it comes to signing over intellectual property rights to Sun (or whatever they ask for in that terrible lawyer speak). I would also have to make a false statement when it comes to my employer. I have no plans to do so.
Anyhow, me adding code would not prevent closures. Sun will probalby only stop adding vanity features once Java got as bad as C++.
Posted by: ewin on August 26, 2006 at 10:52 AM
-
@ewin, first i'm not a Sun employee and second there is more than one Java implementation.
Posted by: forax on August 26, 2006 at 12:53 PM
-
"embed derby in the JDK is a good Think(TM), it's fairly easy for a newbie to use JDBC now"
And there's part of the problem. More people using JDBC who have no idea of how to use it properly, creating and not discarding database resources and after a few days calling themselves "enterprise Java experts" or some such.
But a more important reason to be opposed to it is the ever increasing bloat. Java is starting to look less like a programming language/platform and more like an operating system. When Microsoft decided to include a web browser the world was up in arms about them bundling one product with another, now Sun does basically the same thing (bundling a database engine and a web server with a programming language) and it's supposed to be a good thing?
The hurdle to be overcome to use JDBC is one of the things that prevents people from using it who don't have the knowledge and inclination to do some research into how to properly use it which would lead them to a wealth of available database engines in every price and performance category. At the same time it is one small contribution to keeping the size of the core platform down to something reasonable.
But it's less harmful than closures which make the core language itself more obscure and prone to the creation of poor, impossible to understand, code.
Posted by: jwenting on August 27, 2006 at 12:16 AM
-
I cant see that there is any need for closures, you can do it with inner classes. E.G. the example given:
CharSequence(CharSequence) identity = (CharSequence seq) {return seq; };
Could be:
interface F< V, A > { V e( A ); } // defined in a standard functional library
F< CharSequence, CharSequence > identity = new F< CharSequence, CharSequence >() {
public CharSequence e( CharSequence seq ) { return seq; };
};
The syntax is longer - so instead of inventing something new fix the syntax, e.g.:
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=6389769
Using this proposed syntax the example becomes:
var identity = F< CharSequence, CharSequence >() ( seq ) { return seq; }; };
Pretty much the same as for the closures, no new concepts, much simpler!
Also: Closures = Poor Man's Inner Classes.
Posted by: hlovatt on August 27, 2006 at 09:04 PM
-
Actually, we might not end up using invokedynamic.
Posted by: gafter on September 06, 2006 at 11:17 PM
|