Thursday, March 21, 2013

Pimp My Visitors

One of the most noteworthy features of Xtend 2.4 are the Active Annotations. They allow you to participate in the compile process of Xtend code to the Java source code. In fact, you implement some kind of a mini code generator and hook into the Xtend compiler - and all this via a lightweight library. And the IDE is fully aware of all the changes that you do to the generated Java artifacts. The astonishing about it, that this approach allows you to develop the annotation processor and the client code side by side.

Are you facing a repetitive coding problem and want to automate that? Nothing could be simpler. Just annotate your class and implement an Active Annotation and you are good.

Which brings me to design patterns. Those often require a lot of boiler plate code since these patterns describe a blue print on how several objects interact with each other to solve a specific problem. So they are quite useful but also verbose by definition. One of the most tedious examples is the visitor pattern. Since I actually like to use a visitor to handle heterogeneous data structures (you know, decoupling and externalized traversal can be quite convenient) I decided to write a small annotation that creates all the fluff around this pattern on the fly.

In order to implement a visitor, I just have to annotate the root type in the hierarchy and all the accept methods as well as the base class of the visitor implementation are automatically unfolded. You don't even have to define the base class for the visitor itself. The following small example basically expands to the very same, verbose Java code as in the example on Wikipedia .


Especially amazing is the fact, that this allows to define different kinds of visitors easily. Your accept-method has to take additional arguments? Just list them in the prototype method signature. You want to return a result? Nothing's easier than that - simply declare a different return type. The base implementation for all concrete visitors is already known? Just add the method body to the prototype and it will be moved to the visitor itself. Have a look at the complete example to see how beautiful this approach is. If you want to learn more about Active Annotations, you may want to dive into the documentation on xtend-lang.org and install Xtend to get your hands dirty.

3 comments:

Scott Stanchfield said...

Very cool, Sebastian. I teach Design Patterns at Johns Hopkins and some of the biggest complaints are some of the tedious bits like this (especially in the Visitor pattern). Wish I had thought of generating all those accept methods before ;) [though I do wish people would stop using the Visitor Pattern...]

The only good thing about having to write the same method over and over is that it makes a great demonstration of how the compile-time method signature resolution works (and that java doesn't have dynamic runtime dispatch)

I demonstrate some code generation in the patterns class (and a good bit more in my Android class) using Java annotations, but I'm definitely going to dive in with Active annotations soon.

Scott Stanchfield said...

After looking at the example in more detail, I have a few comments. I think these are important to consider as your examples are demonstrating some bad practices with regard to the Visitor pattern.

Names of visit methods
Your visit() methods should not be named differently based on the parameters. They should all be named simply "visit", using overloading to differentiate. This allows for "fallback" visit methods when new types are added to a hierarchy but not added to the Visitor interface. (Not really an issue when you're generating the visitor interfaces, but helpful to understand the intent of the pattern)

Passing extra parameters to accept
The main idea of the Visitor is that the operation they're performing is self-contained. This means that you never have variations where you need to pass in extra data (like the StringBuilder you're passing for the SpecializedCarElement example). Instead, the visitor that you would pass builds the string and provides a getter method to access it. This keeps the interface simple (one set of accept methods) but has the same flexibility (you have control of the visitor implementation you pass)

All that said, the example is great - it really helped me see how active annotations work.

Unknown said...

Hi Scott,

thanks for the feedback.

I prefer the explicit name for the visit methods since it greatly improves the readability of stack-traces and is less error-prone if you want to delegate to the implementation for the super type of the current case. IDEs may get confused otherwise and decide to removec unnecessary casts etc.

Regarding the additional parameters: I really prefer to pass such state around instead of holding it as an instance field. After all, active annotations finally allow to easily implement such kind of functionality. I think it was not the common case with the traditional pattern because of the overhead on the implementation side.