Message-ID: <1470200746.1619.1369239864826.JavaMail.email@example.com> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_1618_2085856682.1369239864826" ------=_Part_1618_2085856682.1369239864826 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
Last modifi= cation:
This GEP introduces an experimental = new feature in the language known as static compilation. Static co= mpilation can be used when the dynamic features of Groovy are not necessary= and that the performance of the dynamic runtime is too low. The reader mus= t understand that :
Static compilation heavily relies on an= other feature called Static type checking but it is important to understand that they = are separate steps. You can statically type check your code, and still have= the dynamic runtime at work. Static type checking adds type inference to t= he compilation process. This means that, for example, type arguments of met= hod calls are inferred, as well as return types of closures or methods. Tho= se inferred types are used by the checker to verify the type flow of your p= rogram. When it does so, once must be aware that the static checker= cannot behave like dynamic Groovy. This means that even if a prog= ram passes static type checking, it may behave differently at runt= ime.
Groovy supports multimethods. Especia= lly, in dynamic Groovy, target methods are chosen at runtime, in opposite t= o Java which chooses target method at compile time. Let's illustrate the di= fference with an example :
In Java, this code will output "Object", because t= he target method is chosen according to the type of the arguments at compil= e time. The declared type of "o" is Object, so the Object version= of the method is chosen. If you want to call the String version, you have = to define "o" as a "String", or cast o to string in the= method call arguments. Now the same example in dynamic Groovy :
If you run this snippet, you will see that Groovy prints &qu= ot;String". The reason is that Groovy resolves type arguments at runti= me and chooses the most specialized version of a method signature when mult= iple versions are possible. To deal with multiple arguments, Groovy compute= s a distance between the actual type arguments and the declared argument ty= pes of a method. The method with the best score is chosen.
The method= selection process is complex, and makes Groovy quite powerful. It is also = possible, for example, to define metaclasses which will choose different me= thods, or change the return type of a method dynamically. This behaviour is= responsible for a large part of the poor performance of Groovy invocation = times as compared to Java. However, performance has greatly improved with t= he introduction of call site caching in Groovy. Even with those optimizatio= ns, Groovy is far for the performance of a pure static language.
InvokeDynam= ic support is under development and should be introduced in the upcoming Gr= oovy 2.0. What InvokeDynamic allows us to do is to, basically, replace call= site caching with a native "dynamic method dispatch" system dire= ctly implemented by the JVM. It is still uncertain what performance improve= ment we will reach. At best, we could be close to the performance of a stat= ically typed language. However, as some features are still difficult to imp= lement with InvokeDynamic, most likely the performance gain will not be so = high. It is important to talk about it though, because :
However, = InvokeDynamic has a major drawback : it will only be available for people u= sing a Java 7+ JVM. If we want to deliver Java-like performance for Groovy = programs to our users, can we afford leaving most of them without such? Mos= t probably, Java 7 won't be mainstream before two or three years.
R=C3=A9mi Forax, however, created a backport of invokedynamic for= older versions of the JVM. Such a backport relies on bytecode transformati= on to replace invokedynamic instructions with "emulated instructions&q= uot;. This "emulated" mode is great for us Groovy developers, bec= ause it would allow us to write code once and run it on any JVM, but for us= ers, the performance would most probably be bad. To be sure of that, an exp= eriment with backported InDy will be made once invokedynamic support is imp= lemented in Groovy core. The most probable situation, though, is that perfo= rmance of such code will remain far from what a static language could provi= de.
This GEP is there to experiment a static compilation = mode in Groovy. With what we have explained before, you should already unde= rstand that statically typed code implies a different behaviour from dynami= c code. If you expect the statically checked and statically compiled code t= o behave exactly like dynamic Groovy, you should already stop there, or wai= t for invoke dynamic support to expect improved performance. If you perfect= ly understand that statically compiled code means different semantics, then= you can continue reading this GEP, and help us choose the best implementat= ion path. In fact, there are several options that we will explain here.=
The current implementation relies on the static type checker, which perf= orms type inference. This means that with the previous example :
The compiler is able to infer that when the foo met= hod is called, the actual type argument will be a string. = If we compile it statically, the behaviour of this statically compiled prog= ram at runtime will be the same as dynamic Groovy. With such an implementat= ion, we expect most programs to behave statically like they would in dynami= c Groovy. However, this will never be always true. This is why we say this = behaviour is "as close as possible" as the one of dynamic Groovy.=
The drawback of this implementation is that the developer cannot eas= ily know what method the compiler chooses. For example, let's take this exa= mple, extracted from a discussion on the mailing list:
The static type checker infers the type of o2 from = the return type of getXXX, so knows that doIt is called w= ith a String, so you could suspect the program to choose = the foo(String) method. However, doIt is a closure, which= can therefore be reused in many places, and the type of its "x" = argument is unknown. The type checker will not generate distinct closure cl= asses for the different call sites where it is used. This means that when y= ou are in the closure, the type of 'x' is the one declared in the closure a= rguments. This means that without type information on 'x', x is supposed an= Object, and the foo method which will be statically chosen will b= e the one with the Object argument.
While this can be surprising, thi= s is not really difficult to understand. To behave correctly, you must eith= er add explicit type arguments to the closure, which is always preferred. I= n a word, in a statically checked world, it is preferred to limit the place= s where types will be inferred so that code is understood properly. Even if= you don't do it, fixing code is easy, so we think this is not a major issu= e.
The alternative implementation is not to rely on inf= erred types, but rather behave exactly like Java does. The main advantage o= f this is that the user doesn't have 3 distinct method dispatch modes to un= derstand, like in the previous solution (Java, dynamic Groovy, inferred sta= tic Groovy). The major drawback is that the semantics of static Groovy are = not close to the ones of dynamic Groovy. For this reason, this is not the p= referred experimental implementation. If you think this version should be p= referred, do not hesitate to send an email to the mailing list so that we c= an discuss. You can even fork the current implementation to provide your ow= n.
Static comp= ilation is now part of the Groovy 2.0.0 release. You can download the lates= t Groovy 2 releases and test it.
Static compilation is for the moment only s= upported at the method level (do not try to add it to a class) and supports= direct method calls as long as you do not:
For example, you can try the follow= ing snippet :
This code should already run as fast as Java.
Some users have suggested a= nother idea, related to static compilation, which is the "arrow operat= or". Basically, the idea is to introduce another way of calling method= s in Groovy :
While this idea sounds interesting, especially when you want= to mix dynamic and static code in a single method, we think it has many dr= awbacks. First, it introduces a grammar change, something we would like to = avoid as much as possible. Second, the idea behind this operator is to perf= orm direct method calls when you know the type of an objec= t. But, without type inference, you have two problems :
Imagine the following code :=
While the first call can be resolved easily, this is not the= same with the second one. You would have to rewrite your code probably thi= s way to have this work :
Which is not necessary if you use the @CompileStatic annotat= ion :