flexible closures in java with generics

with the upcoming of the new dynamic languages like groovy or ruby, functional programming seems to flow into developer minds of many. one key to it’s success is it’s mighty expressivenes when using closures. even in java world, closures are highly discussed now for future versions of the language.

by now we can use anonymous classes to simulate the behaviour of closures in a similar way, even not so powerfull as with the true lambda calculus behind the idea of closures. first of all, we have an interface named Closure, which ought to represent our code block:

public interface Closure{
    public Object exec( Object arg );
}

now if we have some classes which supports our closure …

public class BooksCollection{	

   private Book[] books;

    public Collection filter( Closure closure ){
         Collection filteredBooks = new ArrayList();

        for( Book book : books ){
             if( (Boolean) closure.exec( book ) ){
                filteredBooks.add( book );
            }
        }
        return filteredBooks;
    }
}

… we can simply define an ad hoc closure to filter some desired books:

Collection booksByGoethe = classcialBookCollection.filter(
    new Closure(){ public Object exec( Object book ){
        return ((Book) book).getAuthor().equals( "Goethe" ); } } );

this solution has some serious drawbacks: one of the strength of closures is it’s unbound and dynamic behavior to any kind of datatypes. you can pass a closure to any datatype who supports closures, where the closure is not restricted to a specific type of it’s arguments nor it’s return type. where you once pass an instance of type Book, you are free to use a closure to some other times, where you will pass instances of another type, let’s say Report. as you have seen in our simple example, in a half typed language like java you can achive a similar freedom by limiting the argument and return types to type Object. but this comes with a risky tradeoff.

1. loss of type safety
the compiler can’t check if your closure really returns an instance of type Boolean back to the BookCollection.
(the compiler can’t also check if the class BookCollection really passes only instances of type Book to the closure)

2. bothersome typecasting
in order to evaluate the passed Book and retrieve some of its properties inside of our closure, we have to cast from Object to Book.
same is true for BookCollection. we have to cast to Boolean in order to decide whether to adopt the current book to the filteredBooks or not.

well this was a somewhat humble solution … before generics.

generics to the rescue

with generics we can now define more flexible closures which exempt us from the bothersome work of typecasting and giving the compiler a chance to check the proper usage.

How do our interface Closure looks like with a generic touch?

public interface Closure<R,A> {
    public R exec( A arg );
}

as you can see, we define two generic types. one for the return type (R) and a second for the type of the argument (A). now this is still straightforward.

whats about our supporting classes? they now have the chance to define, which type of closures they will accept.
in order to make things more interesting, we will now extend the example and introduce a class CollectionUtils, which offers a couple of collection related functions, like filtering, converting or applying some processing to all elements of a collection:

public class CollectionUtils {
    public static <T> Collection<T> filter( Collection<T> source, Closure<Boolean,T> filter ){
         Collection<T> filteredElements = new ArrayList<T>();

         for( T item : source ){
             if( filter.exec( item ) ){
                filteredElements.add( item );
            }
        }
        return filteredElements;
    }

    public static <T,S> Collection<T> convert( Collection<S> source, Closure<T,S> converter ){
         Collection<T> convertedElements = new ArrayList<T>();

         for( S item : source ){
            convertedElements.add( converter.exec( item ) );
        }
        return convertedElements;
    }

    public static <T> void each( Collection<T> source, Closure<?,T> visitor ){

        for( T item : source ){
            visitor.exec( item );
        }
    }
}
 

lets take a closer look at the individual methods.
the filter() method will create a new collection for the books to filter which it will return after processing the source collection. the type of the filtered elements in this collection is of the same type of the elements in the source collection. it’s also the type of the argument, which the closure have to provide. further on, we demand from our closure to return an instance of type Boolean.
what do we have achieved?
first of all, we can use closures in a typesafe way, independent of any concrete type. regardless of filtering books, reports or shop items, you only have to provide a proper closure with the adequate type parameters. let’s look on how to filter books with our new closure:

public class CollectionUtilsTest {
    private Collection<Book> books;
    @Before
    public void setUpBooks(){
         books = Arrays.asList(
            new Book[]{
                new Book( "A Simple One", "Cole", 29.99f ),
                new Book( "New and fresh", "Simmons", 59.99f ),
                new Book( "The Big One", "Cole", 19.99f ),
                new Book( "Foos and Bars", "Adams", 24.99f ),
                new Book( "The Answer", "Iverson", 24.99f ) } );
    }
    @Test
    public void testFiltering() throws Exception{
        Collection<Book> filtered =
            CollectionUtils.filter( books , new Closure<Boolean, Book>(){
                public Boolean exec(Book book) {
                    return book.author.equals( "Cole" ); } } );
        assertEquals( 2, filtered.size() );
    }
}
 

as you can see, we’ve achieved even more: By instantiating a closure with the appropriate type parameters, there is no need to cast the argument. we can directly refer to the correct argument type Book.
(just as well we do not have to cast to Boolean in the method filter() , since it demands a return type Boolean from our closure). now the compiler is also able to check against the correct type parameters, so we have type safety at compile time.

our next method convert() is written in the same manner. this time we allow the closure to determine his return type by himself as he is responsible for the type of the converted elements. thereby the closure also determines the type of the returned collection for the converted elements of the method convert(). further on we link the type of the closure’s argument to the corresponding type of the elements of the source collection, so we are typesafe when we pass the elements to the closure. let’s look at the example, where we want to extract the titles of the books:

@Test
public void testConversion() throws Exception{
    Collection<String> titles =
        CollectionUtils.convert( books , new Closure<String, Book>(){
            public String exec(Book book) {
                return book.title; } } );
    assertEquals( 5, titles.size() );
    assertTrue( titles.contains( "A Simple One" ) );     assertTrue( titles.contains( "New and fresh" ) );     assertTrue( titles.contains( "The Big One" ) );     assertTrue( titles.contains( "Foos and Bars" ) );     assertTrue( titles.contains( "The Answer" ) ); }    

our last method each() offers no spectacular new insights. the only thing to mention is the fact, that it does’nt depend on any return type of the closure. therefore the method does’nt mind about it and express this freely.

summary

as we have seen, generics offer a new dimension to define typesafe closure-like constructs in java without the need of cumbersome and code blowing typecasts.
of course we can’t obtain the same power as with true closures in languages with built-in support for functional programming. but used in moderate doses, there is potential to improve the expressiveness of our code markedly!

Advertisements
Posted in java. 8 Comments »

8 Responses to “flexible closures in java with generics”

  1. Neal Gafter Says:

    Another alternative would be to add true closure support to Java: http://www.javac.info/

  2. Mario Gleichmann Says:

    Neal,

    thanks for your remark.
    of course true closure support would be the better alternative, since we could easily reference the surrounding lexical scope and could express so many ‘operations’ in a more concise way.
    After playin’ a little bit with your prototype, i’m pretty eager to see true closure support in Java 7 … :o)

    Greetings

    Mario

  3. Ricky Clarkson Says:

    Closure seems a bad name; I’d prefer Function.

    I’d prefer it so much I already did it – http://functionalpeas.googlecode.com/svn/trunk/src/fpeas/function/Function.java (root of the project is here: http://code.google.com/p/functionalpeas/ ).

    “by now we can use anonymous classes to simulate the behaviour of closures in a similar way, even not so powerfull as with the true lambda calculus behind the idea of closures.”

    I’m not sure how anonymous classes lack power. I’d say that they lack brevity.

    Also, I’d suggest that you use Iterable instead of Collection in CollectionUtils.

    This frees you to implement filter in a lazy way, i.e., without copying. This is handy when you are dealing with collections that are large, or may be changed (and when the filter should reflect the change).

    I was going to type an implementation of it here, but hasNext would have to peek ahead, which would lengthen the code a bit.

    The ‘each’ method would be more flexible if you made it be able to return stuff. Of course, what do you do when you want it to return nothing? Either do the stuff that you need and define the return type as Void (not void) and the return value as null, OR, return a Runnable.

    I’ve used [] for generics, because there is no Preview button on this blog..

    public static [T,R] R forEach(Iterable[T] source, Function[T,R] function,Function[Pair[R,R],R] operator) { blah }

    The way I would call this is:

    Function[Integer,Double] sqrt=new Function[Integer,Double]()
    {
    public Double run(Integer input)
    {
    return Math.sqrt(input);
    }
    };

    Function[Pair[Double,Double],Double] plus=new Function[Pair[Double,Double],Double]()
    {
    public Double run(Pair[Double,Double] input)
    {
    return input.first()+input.second();
    }
    };

    double sumOfRoots=forEach(Arrays.asList(3,4,5),square,plus);

  4. Mario Gleichmann Says:

    hi Ricky,

    thanks for your comments!

    what’s the critical difference between the name ‘closure’ and the name ‘function’ for you? looking at wikipedia, we found the following definition: ‘In programming languages, a closure is a function that refers to free variables in its lexical context …’
    maybe we think about the same concept (block of code which can refer to it’s defining context, which you can pass to other functions) on different levels. in fact, we ultimately talk about functions with church’s lambda calculus in mind :o)

    anonymous classes in java lack power in two critical ways:

    1. you can’t define a dynamic number of arguments for your method(s) in which the arguments having potentially all different types.

    2. they have restricted access to their lexical context (that is the surrounding method, respectively class instance in which it was defined). anonymous classes can refer only to final variables of its surrounding method, respectively names of its lexically enclosing class (they can refer to them of course, even if the class instance and therefore local final variables of the defining method does’nt exist anymore). beside that, brevity is also part of the power of closures ;o)

    you’re right, using Iterable would made the code more generic, since you only iterate over the elements … but copying the filtered elements was done with full intention, since i wanted to consider the source collection as ‘immutable’ (and maybe we furthermore iterate over an unmodifiable collection).

    thanks also for your example and direction to your project. i will have a deeper look in the next days!

    seems that we have the same goal: reduction of code duplication and verbosity (as you’ve said on your project homepage) and enhancement of the expressiveness of our code :o)

  5. Patrick Wright Says:

    Hi–have you looked at the “Functor” libraries? Just try a Google search–there are a number of them: Commons Functor, JGA, FunctionalJ, Mango. I believe these implement the ideas you’re proposing but as a standard library. JGA supports generics, not sure if the others do. Cheers-Patrick

  6. Mario Gleichmann Says:

    hi patrick,

    thanks for your references! as soon as i’ll have time, i’ll take a look!
    for about the above post, i didn’t want to build a new library of closure supporting services. it should only show how to use generics in order to ease development of closures, reducing boilerplate code an raise readability.
    maybe we can see it more as a technique rather than a full service library :o)

  7. Ricky Clarkson Says:

    magle, Again, I’ve used [] instead of chevrons in this post, and sorry for the delay in replying – I just looked back through my bookmarks and spotted your comment.

    “what’s the critical difference between the name ‘closure’ and the name ‘function’ for you?”

    An interface itself cannot be a closure. Assuming that the only thing that really is a closure in Java is an anonymous class, calling an interface Closure, when it could be implemented as a named top-level class (i.e., there is no surrounding lexical context), seems misleading.

    “you can’t define a dynamic number of arguments for your method(s) in which the arguments having potentially all different types.”

    Java has no syntax for variable numbers of type parameters, this is true, but it needn’t be a problem.

    In Haskell, a function that takes an A and a B and delivers a C is typed as: A -] B -] C, i.e., if you call the function by passing it an A, it returns a new function that takes a B and returns a C. (remember that I’m using [] instead of chevrons!)

    In Java, this can be done as Function[A,Function[B,C]]. Obviously this gets more and more cumbersome with more parameters, e.g., Function[A,Function[B,Function[C,Function[D,E]]]]. I stole an idea from Higher Order Java (http://www.cs.chalmers.se/~bringert/hoj/), in which this is simplified a little – Function2 is defined as (paraphrasing here):

    interface Function2[T1,T2,R] extends Function[T1,Function[T2,R]]{}

    This implicitly supports currying, to curry (which is supplying a subset of the arguments to a function), just do newFunction=function.run(firstParam);

    “anonymous classes can refer only to final variables of its surrounding method”

    This is not a real complaint, as the non-final variable can be emulated, e.g., with a single-element array. If you are writing in a functional way, then you probably don’t want your function to mutate stuff anyway, so again, it’s not a problem. It does take some extra brain cells sometimes to work out how to write the function without mutating stuff, but in my experience the end result is often worth it (simpler).

    “brevity is also part of the power of closures”

    That may be true, but it’s not important for me. I like code to be meaningful. If there’s a lot of meaning, I don’t mind if it’s not brief. If there’s little meaning, I want brevity. E.g., invokeLater{frame.setVisible(true);} has a good signal to noise ratio.

  8. Ricky Clarkson Says:

    I correct myself, currying isn’t quite what I said.

    Currying is converting a function that takes two arguments, into a function that takes one argument, and returns a function that takes one argument.

    E.g., Function[Pair[A,B],C] becomes:
    Function[A,Function[B,C]]


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: