Search code examples
javareflectionclosureslambdaj

Java mechanisms at use in lambdaj closures


Lamdbaj allows the definition of closures in the Java language, various examples can be found here

My question is regarding the underlying Java mechanisms at use, for instance, to define the println closure, the following code is used:

Closure println = closure(); 
{ of(System.out).println(var(String.class)); }

This closure can be subsequently executed via:

println.apply("foobar");

I am curious as to what mechanisms in Java would allow the call to of(...).println(...) to become associated with the println instance itself.

Naturally, the lambdaj source code is available to read but I was hoping for a slightly higher level explanation if anyone has one. My reflection skills go as far as a bit of introspection and executing methods dynamically.


Solution

  • Well, of is presumably a static method which is imported statically so it can be called without the enclosing class name. I expect that var is the same. Both methods must return some type which have the methods subsequently called:

    public class Printable {
      public void println(Var var);
    }
    
    public class Fac {
      public static Printable of(Object o) {
        return new Printable(o);
      }
    
      public static Var var(Class<?> clazz) {
        return new Var(clazz);
      }
    
    } 
    

    All of a sudden:

    Fac.of(System.out).println(Fac.var(String.class));
    

    Is valid Java. Using static imports, hey presto:

    import static Fac.*;
    
    of(System.out).println(var(String.class));
    

    The curly-braces are obviously valid Java as you can add these in any method to aid in defining a lexical sope. This API-design style is called fluent and is best showcased by the JMock testing library.

    By the way, if this is supposed to introduce closures to Java, it's quite ridiculous - the syntax is unreadably awful. Their I/O example actually made me laugh out loud. Try Scala!

    EDIT - the two println calls are associated I believe because the first sequence of calls allow the library to capture the variables which you have passed in as parameters. These are probably captured in some ThreadLocal structure. When you then call a (also presumably static) println method, the library is using this captured data to actually execute the behaviour at a later point. Also testing related, the EasyMock test framework uses a similar mechanism (which uses Java proxies in the background) to capture expected values.