File: visitor.html

package info (click to toggle)
nice 0.9.13-3
  • links: PTS
  • area: main
  • in suites: lenny
  • size: 7,284 kB
  • ctags: 6,893
  • sloc: java: 42,767; xml: 3,508; lisp: 1,084; sh: 742; makefile: 670; cpp: 21; awk: 3
file content (199 lines) | stat: -rw-r--r-- 7,978 bytes parent folder | download | duplicates (4)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
<!doctype html public "-//w3c//dtd html 4.0 transitional//en">
<html>
<head>
   <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
   <meta name="Author" content="Daniel Bonniot">
   <meta name="GENERATOR" content="Mozilla/4.76 [en] (X11; U; OSF1 V4.0 alpha) [Netscape]">
   <meta name="Description" content="Shows how multi-methods advantageously replace the visitor pattern.">
   <meta name="Keywords" content="visitor,pattern,multi-method,multimethod,multiple dispatch">
   <title>Visitor pattern considered useless</title>
<link rel=stylesheet href="style.css">
</head>
<body text="#000000" bgcolor="#FFFFFF" link="#0000EF" vlink="#51188E" alink="#FF0000">

<center>
<h1>
Visitor Pattern Versus Multimethods</h1></center>

<ol>
<h2>
The Visitor Pattern</h2>
The visitor pattern is a programming pattern that has been advocated strongly
for writing code operating on a hierarchy of classes. <a href="http://www.ti.et-inf.uni-siegen.de/Entwurfsmuster/ArtikelImport/osefa/patterns/visitor/intent.htm">A
thorough description is available there</a> from the <i>Design Patterns</i>
book.
<p>A typical example is the definition of operations on an Abstract Syntax
Tree. Here is Java code using a Visitor:
<PRE>
<FONT COLOR="#0000ee">package</FONT> syntax;

<FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">ExpressionVisitor</FONT> 
{ 
  <FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#b7860b">void</FONT> visitIntExp(<FONT COLOR="#b7860b">IntExp </FONT>e); 
  <FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#b7860b">void</FONT> visitAddExp(<FONT COLOR="#b7860b">AddExp </FONT>e); 
} 

<FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">Expression</FONT> 
{ 
  <FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#b7860b">void</FONT> accept(<FONT COLOR="#b7860b">ExpressionVisitor </FONT>v); 
} 

<FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">IntExp</FONT> <FONT COLOR="#0000ee">extends</FONT> <FONT COLOR="#b7860b">Expression </FONT>
{ 
  <FONT COLOR="#b7860b">int</FONT> <FONT COLOR="#cd0000">value</FONT>; 

  <FONT COLOR="#b7860b">void</FONT> <FONT COLOR="#cd0000">accept</FONT>(<FONT COLOR="#b7860b">ExpressionVisitor </FONT>v)
  {
    v.visitIntExp(<FONT COLOR="#8080ff">this</FONT>);
  }
} 

<FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">AddExp</FONT> <FONT COLOR="#0000ee">extends</FONT> <FONT COLOR="#b7860b">Expression </FONT>
{ 
  <FONT COLOR="#b7860b">Expression </FONT>e1, e2; 

  <FONT COLOR="#b7860b">void</FONT> <FONT COLOR="#cd0000">accept</FONT>(<FONT COLOR="#b7860b">ExpressionVisitor </FONT>v)
  {
    v.visitAddExp(<FONT COLOR="#8080ff">this</FONT>);
  }
} 
</PRE>

The interest of this construction is that 
it is now possible to define operations on expressions
by subclassing ExpressionVisitor.
This can even be done in a different package,
without modifying the expression hierarchy classes.

<PRE>
<FONT COLOR="#008b00">// Behaviour can now be defined on Expressions 
</FONT>
<FONT COLOR="#0000ee">package</FONT> tools;

<FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">PrettyPrint</FONT> <FONT COLOR="#0000ee">extends</FONT> <FONT COLOR="#b7860b">ExpressionVisitor </FONT>
{
  <FONT COLOR="#b7860b">void</FONT> <FONT COLOR="#cd0000">visitIntExp</FONT>(<FONT COLOR="#b7860b">IntExp </FONT>e) 
  { 
    <FONT COLOR="#b7860b">System</FONT>.out.print(e.value); 
  } 

  <FONT COLOR="#b7860b">void</FONT> <FONT COLOR="#cd0000">visitAddExp</FONT>(<FONT COLOR="#b7860b">AddExp </FONT>e) 
  { 
    e.e1.accept(<FONT COLOR="#8080ff">this</FONT>); 
    <FONT COLOR="#b7860b">System</FONT>.out.print(<FONT COLOR="#a020f0">&quot; + &quot;</FONT>); 
    e.e2.accept(<FONT COLOR="#8080ff">this</FONT>); 
  } 
}</PRE>

Without visitors, the classes have to be modified each time a new
operations is added.
In this case, a <tt>prettyPrint</tt> member method
would be added to each class.
<p>
Another possibility would be to define a static method
in the new package. But then it would be necessary to test 
the argument with <tt>instanceof</tt> and use downcasts.
In short, lose the benefits of object-orientation.

<br>&nbsp;
<h2>
Shortcomings of the Visitor pattern</h2>

However, the Visitor pattern has serious flaws:
<ol>
<li>
An obvious problem is that the arguments and the return type of visiting
methods have to be known in advance. In this example, to define a <tt>prettyPrint</tt>
function that returns a <tt>String</tt>, a new Visitor class has to be
defined, as well as a new <tt>accept</tt> method <b>in every class of the
hierarchy</b>. And the same job has to be done again to define an evaluation
function that returns an integer. The same problem occurs if the visiting
methods needs parameters.</li>

<li>
The code is more obscure. In particular with recursive calls: in <tt>e.e1.accept(this)</tt>
one cannot see that the call is indeed a prettyprint. One would expect
<tt>prettyPrint(e.e1)</tt> there.</li>

<li>
A lot of code has to be written to prepare the use of visitors: the visitor
class with one abstract method per class, and a accept method per class.
This code is tedious and boring to write.
If we add a new class, the visitor class needs a new method. Furthermore,
it is indeed likely that a new visiting method will need the definition
of a new visitor pattern, as seen in point 1. At the least, several patterns
have often to be written.</li>

<li>
If a visitor pattern has not been written in the first time, the hierarchy
has to be modified to implement it. In particular, if the hierarchy cannot
be modified because you are not allowed to, the visitor pattern cannot
be applied at all.</li>
</ol>

<h2>
Alternative solution with Multimethods</h2>
Here is the same example, using multi-methods, 
in <a href="index.html"><font face="Comic Sans MS">Nice</font></a>. 
As you can see, it is much
shorter and natural, and it solves all the problems above.
<p>
<PRE>
<FONT COLOR="#0000ee">package</FONT> syntax;

<FONT COLOR="#0000ee">abstract</FONT> <FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">Expression</FONT> { } 

<FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">IntExp</FONT> <FONT COLOR="#0000ee">extends</FONT> <FONT COLOR="#b7860b">Expression </FONT>
{ 
  <FONT COLOR="#b7860b">int</FONT> <FONT COLOR="#cd0000">value</FONT>; 
} 

<FONT COLOR="#0000ee">class</FONT> <FONT COLOR="#cd0000">AddExp</FONT> <FONT COLOR="#0000ee">extends</FONT> <FONT COLOR="#b7860b">Expression </FONT>
{ 
  <FONT COLOR="#b7860b">Expression </FONT>e1, e2; 
} 

<FONT COLOR="#008b00">// Behaviour can now be defined on Expressions 
</FONT>
<FONT COLOR="#0000ee">package</FONT> tools;

<FONT COLOR="#b7860b">void</FONT> <FONT COLOR="#cd0000">prettyPrint</FONT>(<FONT COLOR="#b7860b">Expression </FONT>e); 

<FONT COLOR="#cd0000">prettyPrint</FONT>(<FONT COLOR="#b7860b">IntExp</FONT> e) 
{ 
  <FONT COLOR="#b7860b">System</FONT>.out.print(e.value); 
} 

<FONT COLOR="#cd0000">prettyPrint</FONT>(<FONT COLOR="#b7860b">AddExp</FONT> e) 
{ 
  prettyPrint(e.e1); 
  <FONT COLOR="#b7860b">System</FONT>.out.print(<FONT COLOR="#a020f0">&quot; + &quot;</FONT>); 
  prettyPrint(e.e2); 
} 
</PRE>

<h2>
Comparison of the two approaches</h2>
Multi-methods allow to solve the situation at which the Visitor pattern
aims, without carrying its disadvantages:
<ol>
<li>
There is no need to write preliminary code to "prepare the way" for visitors.
This solves points 1, 2 and 4 above.</li>

<li>
The code is shorter and more natural. Recursive calls appear as such.</li>
</ol>

<p><br>The Visitor pattern is a trick to introduce multiple dispatch in
a language that lacks it. However, it raises serious issues. Language support
for multi-methods makes it much easier and elegant to handle the common
situation where the Visitor pattern applies.
<br>&nbsp;
<h2>
General information about <font face="Comic Sans MS">Nice</font> : 
the <a href="index.html">Nice home page</a></h2>
</ol>

</body>
</html>