Quantcast
Channel: uttumuttu
Viewing all articles
Browse latest Browse all 10

Obtaining BGGA Closure Parameter Types at Runtime

$
0
0
Recently Alex Miller has explored the use of BGGA closures for building dynamic visitors. Such visitor builders, and also Ricky Clarkson's closure-based pattern matcher, could be greatly simplified if we could obtain the parameter types of the closures at runtime. More precisely, given a closure {T => void}, where T is a parameterized type, we are interested in knowing the class of T.

Since Java generics are implemented via erasure, the generic parameter types can easily be lost. Some ways of "manually" reifying the types include:

  • Passing around class literals, e.g., String.class and Integer.class.

  • Subclassing a generic class with specified parameter types. The parameter types can then be read off using getGenericSuperclass method of the associated class object. This is the famed Gafter's gadget.
However, in the case of BGGA closures, the information about parameter types is already present and needs no manual reification. There are at least two ways to obtain it:

  • Using reflection to read the type parameters of the invoke method of the closure. In the current (2008-02-26) BGGA prototype, the invoke method is always the first method in the array returned by getMethods of the closure's class object, which simplifies the implementation.

  • Using the getGenericInterfaces of the closure's class object. BGGA closures implement generic interfaces from package javax.lang.function, and the type parameters can be read out similarly as with Gafter's gadget.
Below is an example of the first method. The second method is probably too brittle given its high reliance on the current implementation of the BGGA prototype.

import java.util.Map;
import java.util.HashMap;

class Visitor<T> {
    private final Map<Class,Object> cases = new HashMap<Class,Object>();

    static <T> Visitor<T> make() {
        return new Visitor<T>();
    }

    <U extends T> Visitor<T> add({U => void} block) {
        Class argClass = block
            .getClass()
            .getMethods()[0] // invoke
            .getParameterTypes()[0];

        cases.put(argClass, block);

        return this;
    }

    @SuppressWarnings("unchecked")
    void visit(T arg) {
        Class argClass = arg.getClass();

        {Object => void} block = ({Object => void}) cases.get(argClass);

        if(block != null) {
            block.invoke(arg);
        }
    }

    public static void main(String[] args) {
        Visitor<Object> v = Visitor.make()
            .add({String s => 
                System.out.println("Mm, I love strings!");})
            .add({Integer i => 
                System.out.println("An Integer is fine too");});

        v.visit("Mikko");
        v.visit(24);
    }
}


Viewing all articles
Browse latest Browse all 10

Trending Articles