Visitor Pattern

One of the BehavioralPatterns described by the GangOfFour in the book DesignPatterns.

Intent: Represent an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Am I the only person who finds the VisitorPattern kind of useless? The typical example of the use of the VisitorPattern is an expression evaluator where the actual evaluation of the various operations are encapsulated in the visitor class. The big question here is: When do you really write a new visitor implementation? And if you happen to do so, and you want to add a new operation, all visitor subclasses need to change. In the end, I doubt that the flexibility offered by this pattern is ever used.

You use the visitor pattern implicitly in CommonLisp programming.

  (walk-my-object #'evaluate my-object)

(walk-my-object #'pretty-print my-object)

EVALUATE and PRETTY-PRINT could be ordinary functions or GenericFunctions that dispatch methods on consideration of every parameter type. The VisitorPattern is basically a clumsy emulation of generic functions. Generic functions can readily encapsulate algorithms independently of the objects to which they are specialized. So EVALUATE or PRETTY-PRINT have behaviors that depend on the various types of nodes of MY-OBJECT. There are two levels of dispatch going on: first, the indirection upon the GenericFunctionObject parameter, so that EVALUATE or PRETTY-PRINT is called. And then, there is the OO dispatch on the type of node visited. So what is left is to write methods that specialize EVALUATE or PRETTY-PRINT:

  (defmethod evaluate ((node foo-node-class)) ...)

(defmethod evaluate ((node bar-node-class)) ...)

etc. --KazKylheku

It feels as though you create a very complex framework in order to prepare for something that most probably will never happen, and doesn't that break the DoTheSimplestThingThatCouldPossiblyWork?

Is there anyone that could point to a situation where this pattern is being used successfully, and where it has proved to be flexible and served a useful purpose?

Sure, pretty much every time I use the CompositePattern I have found the VisitorPattern useful. However, I am usually not creating specific implementations for each Leaf type. If I subclass the leaf, it rarely impacts my traversal of the composite so I don't change the visitor implementation. I use visitor adaptors too. For example, I have hierarchically grouped rules in my system. I also have hierarchically grouped nodes (or rule targets). I create a visitor that wraps a visitor to each of these in order to make an inner-product of the node/rule pairs. Seems to do what it's supposed to.

That's exactly the situation I have now. My profs want to see CompositePattern combined VisitorPattern. I still don't know how to combine it in an elegant way.

The OpenSceneGraph library makes extensive use of the VisitorPattern.

VisitorPattern suggests CompositePattern, which smells a great deal like NavigationalDatabase or ObjectOrientedDatabase. In this sense, VisitorPattern might be considered a LanguageSmell - a weak hack to get around the fact that an OOPL lacks FirstClass object-graph management, transform, join, and view operations. For many OOPLs, you'll also be fighting the language to achieve safe concurrency, handle partial-failures during a manipulation, implement persistence and serialization, and enforcing whole-graph consistency rules. That is: where you have a DataBase, you're going to want AtomicConsistentIsolatedDurable properties, and most OOPLs don't offer those (and none offer all of them at once or allow big-step consistency semantics - allowing a temporary breach of consistency so long as it is fixed by the end of transaction - it's almost always small-step class invariants per-method-call). The better solution here is integrating a DataBase, and it is likely worth considering a RelationalDatabase - they perform better than you think, especially if you're forced to use explicit locks or something to handle concurrency.

Sometimes CompositePattern is used to represent independent messages or values with 'immutable' structure, which doesn't have quite so many ACID problems (excepting persistence and serialization concerns). This can be used for MessagePassing in an OOP, especially in combination with concurrency, as such messages may easily cross process boundaries without damage to their semantics. Use of VisitorPattern in this case is essentially a FoldFunction with SideEffects. This is likely useful if the OOPL lacks real support for FunctionalProgramming, but any OOPL would do well to provide FirstClass support for immutable and SideEffect-free message structures to better support distribution, concurrency, and PartialEvaluation.

In some OOPLs, such as ErlangLanguage (which isn't advertised as an OOPL but its FirstClass processes fit the classic DefinitionsForOo), objects are not used to represent messages. In those cases, Object references in messages tend to be part of 'protocol' (handshakes representing connections with communications context, reply-to receivers and continuations for ContinuationPassingStyle, etc.). This fits the notion that OOP is about abstraction of program behavior (representing program elements - NygaardClassification), and not about 'data' abstraction (by which I mean reflecting some state of a real or imagined world that must be tweaked and managed by external observers).

Related: GreencoddsTenthRuleOfProgramming. Note that I probably did not write the above statement. --top
From a discussion about operations on sets of objects over at SetsAndPolymorphism:

[That depends entirely on what you want to do with the results. You might want to collect them. You might want to add them. You might want to average them. You might want to pick the biggest one. I wouldn't tie shape methods to sets. I'd make a visitor or something to traverse the set and do whatever I wanted with the results.]

{But isn't VisitorPattern "kind of useless" according to some opinions on that page? }

[No. Visitor lets me decouple what I want to do with the results of operations on things in sets from the things and the sets. That's kind of useful.]

It is not exactly the poster-boy of simplicity. I have not decided at this point it seems there must be cases where it is useful, but want to hear both sides of the debate.

[How do you mean?]
Would it be fair to draw an analogy between VisitorPattern/Classes and ParameterObject/Methods? I.e. each is externalized (abstracted?) from it's parent "construct" in an effort to simplify them and the design.

Sure. Visitor pattern decouples some behavior from a set of classes and the structure that contains them.

An application of the VisitorPattern has been patented in the UnitedStates. See IbmDoubleDispatchPatent.
I have a "Java OLAP" framework that aggregates values in various ways: sum, average, min, max, count. I implemented a visitor for each kind of aggregation. The data set has an accept(Visitor) method that iterates over all values and calls visitor.visit(value) for each value. At the end the visitor has seen and aggregated all values. To add a new aggregation I just create a new type of visitor, everything else stays the same. Neat!

Chris Treber, ct on ctreber point com
I'm writing a source-to-source converter between two languages. The language I'm converting from supports several operations, including jumping out of an arbitrary number of nested "while" loops, that the destination language does not (natively). Therefore, when converting a "while" statement I have to know if any there are any "evil jump statements" inside its code blocks. The same holds true for "case" statements. This is difficult, because such "evil" statements could be nested within an arbitrary number of if/for/while/case/switch statements. Therefore, I converted all the syntax nodes that potentially contain other blocks of code to accept an arbitrary number of visitors and iterate over their contents with them. In this case, the visitor pattern made for an elegant, robust, easy-to-understand solution.

The visitor pattern isn't exactly necessary, but it's safer than leaving static and reinterpret casts up to the user.

Any situation where you would go.

if( someobject.get_type_info() = otherobject.get_type_info() ) {
	sometype * t = static_cast<sometype*>(&otherobject);

Could be made "cleaner" with some kind of Visitor pattern. For example, an abstract syntax tree is a perfect fit for the visitor pattern.

Variations of this pattern: See also the VariationsOnTheVisitorPattern paper.

Related Topics:
Papers related to the visitor pattern


CategoryPattern CategoryBehavioralPatterns

EditText of this page (last edited January 24, 2013) or FindPage with title or text search