Groovy, Java 8 & Virtual Extension Methods

As some of my daily projects deal with Java, I thought it would be a good idea to dig into some language changes Java 8 will provide. Undoubtedly, Java 8 is well known for introducing Lambda expressions as first-class language constructs. There will be a separate blog post concerning Lambda expressions, however there are certain not so well known ingredients Java needs to provide to do a soft migration to enhance already existing classes with lambda support.

Groovy: DGM

The Groovy programming language already comes with a rather advanced version of Lambda: Groovy closures. Apart from feeling like Lambda expressions, they additionally provide features to modify method delegation. This functionality has to be provided in order to allow the creation of lean DSLs, it is a key-feature for creating Groovy-based domain-specific languages. One advantage of closures being first-class language citizens is their applicability in collection classes. This is by far not the only use-case, but its one that hits core-API developers right in their face: how to modify already existing interfaces and classes without breaking already existing byte-code? Groovy did the trick by introducing the so-called "Default Groovy Methods". This term refers to a special set of static methods indirectly extending core Java classes such as java.lang.Object [0] by the all-known each method taking a groovy.lang.Closure has the first parameter.
 

def l = [1,2,3,4]

l.each { println it } // calls DefaultGroovyMethods.each(T, Closure)

 
Another term for this kind of methods is static extension methods (see C# 4.0 [1]). But what happens when the compiler discovers a DGM method call? Whenever there is a tuple (instance, methodName, arguments) it will be executed against the static method DefaultGroovyMethods#(, ). Groovy supports dynamic method invocation, that is, the actual parameter type is taken into the account on method candidate resolution. As Groovy comes with a meta-model to implement its dynamic features on top of JVM byte-code, extending core Java classes can be done as part of these mechanisms. But what about Java?

Virtual Extension Methods

To support Lambda in already existing classes without breaking existing binary code, a new language feature has been introduced in Java 8: virtual extension methods [2][3] [4]. Let's start with Java interfaces. According to the Java language specification an interface is
[An interface declaration] introduces a new reference type whose members are classes, interfaces, constants, and abstract methods. This type has no implementation, but otherwise unrelated classes can implement it by providing implementations for its abstract methods.
However, with virtual extension methods, interface method declarations can specify default method implementations and therefore become so-called extended interfaces with one or more "virtual" extension methods. The term "virtual" might be confusing for those who are not quite familiar with JVM internals or the Java language specification. It refers to the terminated method invocation method during compilation. Non-private and non-super instance methods are said to be virtually invoked. Let's have a look at our first virtual extension method:
 

interface A {
    void m() default { System.out.println("Hello, you."); }
}

class C implements A {}

C c = new C();
c.m();

 
The syntax for specifying a default implementation is to use the default keyword followed by a code block. This choice has been made against inline method declarations to outpoint the difference between method declarations in interfaces and classes. As the interface method provides a default implementation, applying the abstract keyword on such methods is not allowed. As a matter of fact, extended interfaces come closer to "traits" or "mixins" as found in other programming languages or abstract classes in Java. Compared to abstract classes, extended interfaces allow multiple inheritance.
 

interface A {
    void m1() default { System.out.println("Hello, you."); }
}

interface B {
    void m2() default { System.out.println(" ... "); }
}

class C implements A, B {}

C c = new C();
c.m1();
c.m2();

 
Brian Goetz is keen to mention virtual extension methods being more a tool for library developers to offer smooth API evolution keeping binary-compatibility with previous API versions than being used as "traits" or "mixins". Let's have a look at the classic diamond inheritance problem:
 

interface Base {
    int m();
}

interface A extends Base {
    int m() default { return 100; }
}

interface B extends Base {
    int m() default { return 200; }
}

class C implements A, B {}

 
This example does not compile as the compiler detects two candidates for potential method invocation. What if C would be an interface, how could we redefine #m() to call the virtual extension method of B#m()?
 

interface Base {
    int m();
}

interface A extends Base {
    int m() default { return 1; }
}

interface B extends Base {
    int m() default { return 2; }
}

interface C extends A, B {
    int m() default { return B.super.m(); }    
}

class CImpl implements C {}

 
Super method implementations can be invoked with <Interface-Name>.super.<Method-Name>. This doesn't solely work for interfaces, but also concrete and abstract classes.
 

interface Base {
    int m();
}

interface A extends Base {
    int m() default { return 1; }
}

interface B extends Base {
    int m() default { return 2; }
}

class C implements A, B {
    public int m() { return B.super.m(); }    
}

 
Another way of effecting the method dispatch is to remove the inherited default implementation.
 

interface C extends B, A {
    int m(); // <-- removes A & B's default implementation

}

class CImpl implements C {
    public int m() { return 42; }
}

 

The Java 8 Collection Class Lambda Extensions

Now let's see how virtual extension methods look in the wild when being used in 8.0's Iterable<T> extended interface:
 
    // ...


    /**
     * Returns the first element from this Iterable. Depending on the source
     * type of this Iterable repeated calls may-or-may-not return the same
     * element.
     *
     * @return an element of the collection
     * @throws NoSuchElementException if this Iterable contains no elements.
     *
     */
    T getFirst() default {
        return Iterables.getFirst(this);
    }

    // ...


    /**
     * Returns {@code true} if any of the elements match the provided predicate.
     *
     * @param filter a predicate against which returns {@code true} for
     * matching elements.
     * @return {@code true} if any elements returned {@code true} for the
     * provided predicate.
     */
    public boolean anyMatch(Predicate<? super T> filter) default {
        return Iterables.anyMatch(this, filter);
    }

    // ...


 
#getFirst() returns the first element for this Iterable. Although the virtual extension method has been added to a widely used Java interface, already existing binaries won't break when being executed against the new Java runtime environment. Even if a custom Iterable implementation would define a custom getFirst() method, method resolution would dispatch to the custom method. #anyMatch(Predicate) takes an instance of java.util.functions.Predicate as first parameter, whereby this interface itself has a bunch of virtual extension methods and - by the way - already hints why extension methods play an important role when it comes to Lambda expressions (which will be covered in a separate article :-)). [tested with OpenJDK Runtime Environment (build 1.8.0-ea-lambda-nightly-h1171-20120911-b56-b00)] [5]

Conclusion

"Interfaces do not hold method implementations" is not true anymore, at least with the prospective spread of Java 8. Virtual extension methods resemble a new inheritance mechanism, aligned between abstract classes and pure interfaces and primarily used to migrate already existing core Java classes without breaking binary compatibility with existing code.

[0] org.codehaus.groovy.runtime.DefaultGroovyMethods
[1] C# Programming Guide: Static Extension Methods
[2] Brian Goetz: Virtual Extension Methods
[3] Brian Goetz: Interface Evoluation via Virtual Extension Methods
[4] JSR 335 - Lambda Expressions for the Java Programming Language
[5] JDK 8 Lambda Build