The '''Visitor Pattern''' is an [OO] [Design Pattern] that makes it easy to add new operations to a set of related classes without having to modify each class to add the new method. It is somewhat related to pattern matching and [algebraic types]. General discussions at [http://en.wikipedia.org/wiki/Visitor_pattern] and [http://c2.com/cgi/wiki?VisitorPattern]. Here is a simple example in Tcl to demonstrate the idea. The example here will be a simple OO tree representing integer arithmetic expressions (similar to [expr], but much simpler). First, we define the nodes that represent each class, and give each a ''visit'' method: ====== package require XOTcl 1.5 namespace import xotcl::* # A dummy Term class as superclass Class Term # Integers Class Int -superclass Term Int method init val { my set val $val } Int method visit v { $v visitInt [my set val] } # Addition Class Add -superclass Term Add method init {a b} { my set a $a; my set b $b } Add method visit v { my instvar a b $v visitAdd [$a visit $v] [$b visit $v] } # Multiplication Class Mul -superclass Term Mul method init {a b} { my set a $a; my set b $b } Mul method visit v { my instvar a b $v visitMul [$a visit $v] [$b visit $v] } # Create an example: t1 = (12 + (3 * 4)) Add t1 [Int new 12] [Mul new [Int new 3] [Int new 4]] ====== We can now use these ''visit'' methods to define as many operations as we want over our complex data-type: ====== # Pretty printer Object pprint pprint proc visitInt val { return $val } pprint proc visitAdd {a b} { return "($a + $b)" } pprint proc visitMul {a b} { return "($a * $b)" } # Simple interpreter/calculator Object calc calc proc visitInt val { return $val } calc proc visitAdd {a b} { expr {$a + $b} } calc proc visitMul {a b} { expr {$a * $b} } # Example: puts "[t1 visit pprint] = [t1 visit calc]" #=> (12 + (3 * 4)) = 24 ====== ---- See also [A lambda calculus interpreter with arithmetic] for an alternative to the visitor pattern. [Lars H]: I still can't help but feeling this is just [data is code], but with extra indirection (sort of turning itself inside out at every step) to make it fit into an [OO] framework. Which is natural, I suppose, if OO is your primary mechanism for structuring stuff… However, Tcl generally favours functional idioms over OO-idioms. [NEM]: Not really. It's just a way of defining a generic traversal ([fold]) over an inductively defined datatype. As programming languages are also inductively defined, then it is not surprising that it looks similar (code is data, after all). The advantage that would be claimed for the OO representation, as with all things OO, is that it nicely abstracts away the specifics of the concrete representation. A generic fold operation also does this. Treating data as code doesn't do this, as if you change the representation then everything breaks (e.g., if you decide to add source line/column annotations to each term). Of course, you could define a fold procedure (much like the one in the lambda-calc interpreter) that treated data as code ''within that procedure'' (and hid this aspect from clients), which would make pattern matching quite simple and fast, but I think I still prefer an explicit pattern matcher (especially if it can match complex sub-terms). ---- !!!!!! %| [Category Example] | [Category Design Pattern] |% !!!!!!