views:

423

answers:

2

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.

+2  A: 

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.

oxbow_lakes
+1. After 3 years of C++ I thought I knew about ugly closures, but *God almighty*...
David Seiler
Thanks, I have indeed switched to Scala for most of my active development now. This still confuses me though, I understand the static import element, my puzzlement is how the call to of(...).println(...) is somehow associated with the instance 'println' defined before it, in my opening example.
pyo
OK - I've edited my answer as I think I know how this is probably happening
oxbow_lakes
Fantastic, stumbled right into ThreadLocal buried in some closure/proxy generation in the lambdaj source code after you said it, thanks.
pyo
Not a bad deduction then, considering how many beers I've had `:-)`
oxbow_lakes
The order works as such: Closure constructor registers the instance as the newest one created in the current thread (the ThreadLocal), then the subsequent calls to of(...) and var(...) cause proxies to be generated and attached to the current thread's latest Closure instance. Simple when you know how ;)
pyo
+3  A: 

I am Mario Fusco and I am the main developer of the lambdaj library.

First of all I would like to clarify something: lambdaj is not intended to replace any functional language. As I said last week in my speech at the Jug of Zurich if you have a chance to use Scala, go for it and never look back. Here you can find a resume of my speech where it is clearly stated that:

http://ctpjava.blogspot.com/2009/10/lambdaj-new-trends-in-java.html

I am an happy Scala developer too. But sometimes you are just obliged to develop in Java (in my experience, in the real world, about the 80% of times you cannot choose in which language you have to write your code) and in this case some of the lambdaj features could be helpful (or I hope so). I just wanted to bring to Java some functional features that are totally missing. Of course the result is not completely satisfying mainly due to the limitation imposed by Java itself.

As for the internal lambdaj mechanism, yes it uses a ThreadLocal in order to achieve that result. If you have other questions, curiosities or even better suggestions and constructive critics about lambdaj maybe you could be interested to register yourself to the lambdaj mailing list here:

http://groups.google.com/group/lambdaj

Bye Mario

Mario Fusco