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.
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.