Visitor Pattern

One of the Behavioral Patterns described by the Gang Of Four in the book Design Patterns.

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.

wiki.cs.uiuc.edu (times out)


Am I the only person who finds the Visitor Pattern kind of useless? The typical example of the use of the Visitor Pattern 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 Common Lisp programming.

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

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

EVALUATE and PRETTY-PRINT could be ordinary functions or Generic Functions that dispatch methods on consideration of every parameter type. The Visitor Pattern 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 Generic Function Object 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)) ...)

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 Do The Simplest Thing That Could Possibly Work?

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 Composite Pattern I have found the Visitor Pattern 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 Composite Pattern combined Visitor Pattern. I still don't know how to combine it in an elegant way.

The Open Scene Graph library makes extensive use of the Visitor Pattern.


Visitor Pattern suggests Composite Pattern, which smells a great deal like Navigational Database or Object Oriented Database. In this sense, Visitor Pattern might be considered a Language Smell - a weak hack to get around the fact that an OOPL lacks First Class 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 Data Base, you're going to want Atomic Consistent Isolated Durable 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 Data Base, and it is likely worth considering a Relational Database - they perform better than you think, especially if you're forced to use explicit locks or something to handle concurrency.

Sometimes Composite Pattern 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 Message Passing in an OOP, especially in combination with concurrency, as such messages may easily cross process boundaries without damage to their semantics. Use of Visitor Pattern in this case is essentially a Fold Function with Side Effects. This is likely useful if the OOPL lacks real support for Functional Programming, but any OOPL would do well to provide First Class support for immutable and Side Effect-free message structures to better support distribution, concurrency, and Partial Evaluation.

In some OOPLs, such as Erlang Language (which isn't advertised as an OOPL but its First Class processes fit the classic Definitions For Oo), 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 Continuation Passing Style, etc.). This fits the notion that OOP is about abstraction of program behavior (representing program elements - Nygaard Classification), 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: Greencodds Tenth Rule Of Programming. Note that I probably did not write the above statement. --top


From a discussion about operations on sets of objects over at Sets And Polymorphism:

[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 Visitor Pattern "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 Visitor Pattern/Classes and Parameter Object/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 Visitor Pattern has been patented in the United States. See Ibm Double Dispatch Patent.


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:

Acyclic Visitor -- eliminates cyclic dependencies, sometimes slower than normal visitors

Selector Generating Visitor -- avoids modifying visited classes

Hierarchical Visitor Pattern -- another way to handle the pretty-printing problem

Independent Visitor Pattern -- another way to eliminate cyclic dependencies

Default Visitor Pattern -- generalization of the Null Object And Visitor pattern

Related Topics:

Null Object And Visitor -- combining Null Object with the Visitor Pattern

Pattern Hatching -- see pages 36, 81-84

Translator Pattern == alternative visitor style used in Functional Programming

Resource Releases Resource -- can a single object accept a visitor?

Java programmers will find Nested Exception useful.


Papers related to the visitor pattern

Propagators


Related:


See original on c2.com