Concise EDSL Closures in Java
Written by Jevgeni Kabanov on May 19, 2008 – 11:43 amThis trick was pointed to me (without the ThreadLocal part) by Rein Raudjärv, who saw it used in jMock.
The problem with Java “closures” aka anonymous inner classes being a tad too ugly is a well known one, but this semi-solution seems to be quite unused. Although you can apply the same principle for many situations it’ll work best for embedded DSLs.
Let’s start by defining an EDSL intefrace:
-
public interface DSL {
-
-
DSL doSomething();
-
DSL doSomethingElse();
-
DSLPreClosure closure();
-
}
As you can see we separated the actual closure application in a separate interface:
-
public interface DSLPreClosure {
-
DSL apply(DSLClosure closure);
-
}
The reason for that is that we want to use closures without defining a method in the anonymous inner class:
-
public class Test {
-
new DSLImpl()
-
.doSomething()
-
.closure().apply(new DSLClosure() {{
-
dsl
-
.doSomething()
-
.doSomethingElse();
-
}})
-
.doSomethingElse();
-
}
-
}
What happens is that we abuse a little used Java feature — initializers. If you put a block in the body of a class definition it will be executed right after the constructor. In our case we construct a new subclass of DSLClosure and immediately add an initializer:
-
new DSLClosure() {
-
//Initializer starts here
-
{
-
//Closure body goes here
-
}
-
//Initializer ends here
-
};
Of course while this allows to execute a block of code with fewer symbols to write, we still need to somehow pass parameters. Note, that since the initializer executes inside the constructor call, it will be executed before the actual apply() method is called. Therefore we make use of the ThreadLocal class to pass the parameters inside the call:
-
public class DSLImpl implements DSLWithClosure {
-
-
public DSL doSomething() {
-
//Do something…
-
return this;
-
}
-
-
public DSL doSomethingElse() {
-
//Do something else…
-
return this;
-
}
-
-
public DSLWithClosure closure() {
-
curDSL.set(this);
-
return this;
-
}
-
-
public DSL apply(DSLClosure closure) {
-
curDSL.set(null);
-
return this;
-
}
-
}
Finally the DSLClosure exposes the ThreadLocal parameter as a protected field:
-
public class DSLClosure {
-
protected DSL dsl =
-
(DSL) DSLImpl.curDSL.get();
-
}
Of course, for the sake of correctness we should also allow nesting closure calls on the same thread, so we should use a stack inside ThreadLocal, but this is left as an exercise to the reader :)
Tags: dsl, java
Posted in creative | 5 Comments »
5 Comments to “Concise EDSL Closures in Java”
Leave a Comment
Additional comments powered by BackType
May 19th, 2008 at 12:03 pm
This article needs a concrete example comparing this method to the standard functor closure.
May 19th, 2008 at 2:47 pm
It’s not an article, it’s a blog post and what do you mean under standard functor closure?
BTW, anonymity is not welcome on our blog.
May 19th, 2008 at 9:30 pm
I smell a wacky hack :)
jMock kind of have its merits because they try to keep the wackyness to themselves, but I was still scratching my head when I read their tutorial.
When I look at that api, I get a feeling that there’s too many rocks for the bugs to hide under. I’ve found that simpler code produce simpler bugs, so I think I’ll skip this one and wait with closures until Java 7 when we hopefully get a more clear-cut syntax for the concept.
May 20th, 2008 at 12:16 am
Christian: It is highly unlikely that closures will go to Java 7 with the current state of affairs. For the reasons check out this: http://getahead.org/blog/joe/2008/05/19/big_question_for_sun.html .
May 21st, 2008 at 12:00 am
“highly unlikely” sounds exagerated in my ears :) Last I looked, the closures group on openjdk.org looked live and kicking. They have a good road map that extends till august and expecting to produce a final prototype. If I remember correctly, Java 7 is scheduled for release at beginning of next year. To me, this looks like an entierly reasonable timeframe for getting closures in Java 7. I got my fingers crossed.