Visitor pattern with closures

10

I’ve been playing around a bit with how having closures in Java 7 would alter some design patterns. I’m doing a talk on design patterns for Java One so hoping to do some stuff on this for the talk.

Here’s one version of Visitor with closures. I’m not too happy with it yet. There’s no Visitor interface, I’m just using a closure to handle the visitor callbacks. The downside to that is that I’ve lost the double-dispatch part. I suspect this is probably fine for many common visitor cases and sucks for others.

The main Visitable interface now just takes a block:

public interface Visitable {
void accept({ Visitable => void } block);
}

And concrete and composite nodes have accept methods like this:

public interface Node extends Visitable {}

public class CompositeNode implements Node {
private List nodes = new ArrayList();

// …

public void accept({ Visitable => void } block) {
block.invoke(this);
for(Node node : nodes) {
node.accept(block);
}
}
}

public class ConcreteNode implements Node {
// …

public void accept({ Visitable => void } block) {
block.invoke(this);
}
}

And you can use it like this:

public class Test
{
public static void main(String[] arg) {
CompositeNode n = new CompositeNode();
n.addNode(new ConcreteNode());
n.addNode(new ConcreteNode());

List strings = new ArrayList();
n.accept({ Visitable v =>
if(v instanceof ConcreteNode) {
strings.add(((ConcreteNode)v).getName());
}
});

System.out.println(strings);
}
}

I’d like to take advantage of double-dispatch to “choose” one of a family of blocks that might apply but seems like that takes you in the direction of having a Visitor again with one method per concrete type and that seems worse than the non-closure version.

Thoughts and ideas?

Comments

10 Responses to “Visitor pattern with closures”
  1. Some interesting perspective on closures and visitors in a dynamic language like Groovy.

  2. Neal Gafter says:

    That’s not the visitor pattern, that’s an internal iterator. The visitor pattern is all about double dispatch, not traversing something.

  3. Andrew says:

    I’m not sure that closures are a magic bullet in this circumstance. The loss of double dispatch and multiple ‘visit strategies’ is independent of the closures, and more a reflection of your desire to reduce the amount of code.

    I’d be more inclined to do the full Visitor interface, DefaultTreeVisitor implementation, and then do subclasses of that for whatever prefab accessors I was after – eg eachConcreteNode. That way I would still have the flexibility of the Visitor pattern if it was required.

    As an aside, the language feature that collapses the Visitor pattern is dynamic dispatch -and closures doesn’t give us that.

  4. Alex says:

    @Neal/Andrew, fair enough – what I’m trying to work my way into is whether you can leverage closures to make a better visitor. Maybe the answer is no. :)

  5. Neal Gafter says:

    I believe the answer is yes (you can leverage closures to make a better visitor), but not this way. Instead write a fluent builder that builds a visitor by aggregation of closures, each of which can accept one node type. This improves the client, but the implementation of the pattern in the nodes is the same as usual.

    Would you like me to elaborate this in detail?

  6. @Alex.
    One of the things I do when writing visitors is to make the accept method really stupid:
    all implementation just have visitor.visit(this). The traversal should be task of the visitor. If I need reusable traversals, I create visitor guides:

    class DepthFirstNodeVisitorGuide implements NodeVisitor{
    private final NodeVisitor guest;

    public DepthFirstNodeVisitorGuide(NodeVisitor guest){
    this.guest = guest;
    }

    public void visit(ConcreteNode node){
    node.accept(guest);
    }

    public void visit(ConcreteNode node){
    for(Node child: node.getChildren()){
    node.accept(this);
    }

    node.accept(guest);
    }
    }

    If you want to apply it, you can say something like this:

    node.accept(new DepthFirstNodeVisitorGuide(new PrintNodeVisitor());

    @back on subject.
    The last example you gave (with the ‘if(v instanceof ConcreteNode)’) typically is something you would not see with a visitor. The question is: it is possible to lift on a different dynamic dispatching mechanism other than the polymorphic dispatch, or to use that polymorphic dispatch for closures.

    It is a shame that Java has so many features but not something ‘simple’ as multi-dispatch.

  7. Alex says:

    @Neal – gotcha, I’ll give that a shot and you can tell me how I did. :)

    @Peter – yeah, I know. If you take a look at my older visitor article (linked above), you’ll see a full treatment of the navigation issue.

  8. Mark Mahieu says:

    I’ll be curious to see what you come up with as a ‘Visitor Builder’ – I was planning to write a short blog entry on that subject myself. The ability to modify local variables and (in BGGA) use non-local returns would make some of my existing uses of the Visitor pattern much simpler…

Trackbacks

Check out what others are saying about this post...
  1. [...] « Visitor pattern with closures | Home | [...]