Keywords: current

Next: 1.10.4 Polymorphic Visitors with Up: 1.10 The Visitor Pattern Previous: 1.10.2 Openness in Data

## 1.10.3 Polymorphic Visitors

In our application of the visitor pattern above, the `for` methods of the visitor classes and the `accept` methods for the `ArithExpr` classes returned values of type `int`. This convention is acceptable as long as all the computations we ever want to perform over `ArithExpr`s have integer results. But if not, we are forced to declare a new interface visitor type and new `accept` methods for each distinct result type. Since the whole point of the visitor pattern is to avoid having to modify a data type every time we wish to perform some new computation over it, we have a potential problem.

We can address this problem by redefining the `for` and `accept` methods so that they return a more general type. Before getting into the details, let's step back and give visitors a more general definition.

A visitor is an object containing

- a concrete description of an operation on composite data, with a separate method for processing each alternate form of the data; and
- the argument values required by the operation.

The properties common to all visitors for a particular composite type are collected in corresponding the visitor interface. Any arguments that are processed by a particular visitor are typically stored in fields declared in the corresponding visitor subclass to avoid compromising the generality of the interface. A typical visitor interface has the form

    interface Visitor {
      // a "for" method for each concrete
      // subclass of the visited class
      Object forC1(...);
      .
      .
      .
      Object forCn(...);
    }

We use `Object` as the return type of the `for` methods so that we can accommodate concrete visitor classes that produce almost any type of result. This convention exploits the polymorphism inherent in class inheritance: every object belongs to all of the types associated with its superclass, super-superclass, etc. Since the class `Object` is perched at the root of the class hierarchy, all objects belong to the type `Object`, and support the operations defined in class `Object`. The only types that do not belong to `Object` are the primitive types like `int`. Fortunately, we can get around this by using the corresponding wrapper classes (e.g. `Integer` instead of `int`). In the event we want a visitor operation to have a `void` return type, we can either return the `null` reference or the only instance of a singleton class `VoidType`.1.9

Let us return to our `ArithExpr` example. We can generalize our visitor class as follows:

    abstract class AE { // AE is short for ArithExpr
      abstract Object accept(Visitor v);
    }

    class Const extends AE {
      /* fields */
      int value;

      /* constructor */
      Const(int v) { value = v; }

      /* getters */
      int getValue() { return value; }

      /* toString */
      public String toString() {
        return Integer.toString(value);
      }

      Object accept(Visitor v) {
        return v.forConst(this);
      }
    }

    . . .

The code for the `Sum` and `Prod` ares nearly identical except for the fact that the `accept` methods in those classes respectively invoke the `forSum` and `forProd`, methods of the `Visitor` argument `v`. They all have `Object` as their return type.

Next: 1.10.4 Polymorphic Visitors with Up: 1.10 The Visitor Pattern Previous: 1.10.2 Openness in Data