Java Reference
In-Depth Information
written in a single class, and not distributed among the various node types
(see Exercise 20).
A phase is thus crafted by writing
methods in the phase's class—one
for each kind of node for which some action must be performed. An example
of this style of code is shown in Figure 2.14 on page 52. A phase
visit
f
then
performs its work for a particular node
n
in response to the method call:
f
.
visit( AbstractNode
n
)
Most object-oriented languages use
single dispatch
to determine which
visit
method should be invoked in response to the above method call. The dispatch
is based on the
actual type
of the receiver object
f
. Unfortunately, single dispatch
finds a match for
based on the
declared type
of its parameters at the call
site. Thus, if a phase contained a method
visit
( IfNode
n
), that method would
not be invoked on an actual IfNode, because the match is based on the declared
type (AbstractNode)ofthesuppliedparameter.
While other solutions are possible (see Exercises 20 and 21), invoking
visit
visit
based on the compiler's phase
fand
a the supplied node
n
's
actual
type requires
double dispatch
(a limited form of
multiple dispatch
). The
visitor pattern
achieves a formof double dispatch for languages that o
er only single dispatch.
The visitor pattern enables phase- and node-specific code to be invoked cleanly,
while aggregating the functionality of a phase in a single class. Figure 7.23
illustrates the application of the visitor pattern for our example. The code is
organized as follows:
ff
•
Every phase extends the Visitor class, as shown at Marker
30
,sothatit
inherits the
visit
(AbstractNode
n
)method.
•
Every concrete node class includes the method shown at Markers
31
,
32
,and
34
that
accepts
a visitor and accomplishes double dispatch as
described below.
While the inclusion of the
method in every node class seems
redundant, it cannot be factored into a common superclass, because the
type of
this
must be specific to the visited node.
accept
As an example, consider the invocation of
f
.
visit(AbstractNode
n
)when
f
is an instance of TypeChecking and
n
is an instance of PlusNode. Multiple
dispatch is accomplished as follows:
•
The inherited method
(AbstractNode
n
)atMarker
28
is invoked,
with
this
bound to the TypeCheckingphase.
visit
Marker
29
invokes
n
.
accept(
this
). Although
n
is declared of type
AbstractNode, single dispatch will invoke the
•
accept
method that is
most specialized to the actual type of
n
.