Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added experimental jar
Excerpt
hiddentrue

Groovy Enhancement Proposal

Metadata

Number:

GEP-10

Title:

Static compilation

Version:

1 2

Type:

Feature

Status:

Draft

Leader:

Cédric Champeau

Created:

2011-11-23

Last modification:

2011-1112-23

Abstract: Static compilation

...

Groovy supports multimethods. Especially, in dynamic Groovy, target methods are chosen at runtime, in opposite to Java which chooses target method at compile time. Let's illustrate the difference with an example :

Code Block

public void foo(String arg) { System.out.println("String"); }
public void foo(Object o) { System.out.println("Object"); }

Object o = "The type of o at runtime is String";
foo(o);

In Java, this code will output "Object", because the target method is chosen according to the type of the arguments at compile 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 :

Code Block

void foo(String arg) { println 'String' }
void foo(Object o) { println 'Object' }

def o = 'The type of o at runtime is String'
foo(o)

...

The current implementation relies on the static type checker, which performs type inference. This means that with the previous example :

Code Block

void foo(String arg) { println 'String' }
void foo(Object o) { println 'Object' }

def o = 'The type of o at runtime is String'
foo(o)

...

The drawback of this implementation is that the developer cannot easily know what method the compiler chooses. For example, let's take this example, extracted from a discussion on the mailing list:

Code Block

void foo(String msg) { println msg }
void foo(Object msg) { println 'Object' }

def doIt = {x ->
  Object o = x
  foo(o)
}

def getXXX() { "return String" }

def o2=getXXX()
doIt o2   // "String method" or "Object method"????

...

The code is currently in early experimental mode. This means that the implementation is far from complete, and likely to crash your JVM. Be warned. However, if you want to test static compilation and understand the semantics differences, feel free to checkout the experimental-static-compiler branch from Git.

Testing

Alternatively, using Groovy 2.0.0-beta-2, you can download the attached jar and add it to your classpath to activate the @CompileStatic annotation. Note that you must use groovy.jar (not groovy-all.jar) and the additional jar with the annotation must be first in the classpath, because it overwrites classes from standard Groovy.

@CompileStatic

Static compilation is for the moment only supported 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 following snippet :

Code Block

@groovy.transform.CompileStatic
int fib(int i) {
    i < 2 ? 1 : fib(i - 2) + fib(i - 1)
}

...

Some users have suggested another idea, related to static compilation, which is the "arrow operator". Basically, the idea is to introduce another way of calling methods in Groovy :

Code Block

obj.method() // dynamic dispatch
obj->method() // static dispatch

...

Imagine the following code :

Code Block

void write(PrintWriter out) {
   out->write('Hello')
   out->write(template())
}

def template() { new MarkupBuilder().html { p('Hello') } }

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 this way to have this work :

Code Block

void write(PrintWriter out) {
   out->println('Hello')
   String content = template() // dynamic call, implicit coercion to string
   out->println(content) // static method dispatch based on declared types only
}

def template() { new MarkupBuilder().html { p('Hello') } }

Which is not necessary if you use the @CompileStatic annotation :

Code Block

@CompileStatic
void write(PrintWriter out) {
   out.println('Hello')
   out.println(template())
}

def template() { new MarkupBuilder().html { p('Hello') } }

...