Monday, August 31, 2009

The post hoc visitor

The visitor pattern is an excellent way to separate concerns, by moving operations on a hierarchy of objects out of the hierarchy itself. Unfortunately it suffers from two major flaws:

  1. You need to declare and implement the Visit method on each class in the hierarchy, which is not only wasteful of code, but also impossible if you don't have control over the class hierarchy (e.g. it's in an external module).

  2. You need to implement a receiver method for every node on every visitor, even if the visitor handles a whole sub-hierarchy in the same way.

What to do? Well, Python handles this extremely well. You can inject virtual methods into the class hierarchy, even after instances have been created, as follows:

ASTNode.VisitOptimizer = classmethod(lambda t: None)
ValueNode.VisitOptimizer = classmethod(lambda t: t.Value)
ExpressionNode.VisitOptimizer = classmethod(optimizeExpression)

Calling node.VisitOptimizer will dispatch to the appropriate method.

Can this be done in C#? Perhaps in version 4: the jury is out. What about extension methods, I hear you ask? Don't bother. Extension methods match the declared type rather than the actual type, for various good if unfortunate reasons. In versions prior to 4, the best method I've come up with is to write a facilitator class that uses reflection to find the best (i.e. most closely-typed) method in the visitor, and calls that. Needless to say, this is heavy.

Anyone got a better idea?