9.2. InterpreterOne use of trees is to represent expressions in a programming language. As in the previous section, the expression type is represented by an abstract class, with each kind of expression represented by a subclass. There is an abstract method to evaluate an expression, and each subclass implements the method as appropriate for the corresponding kind of expression. With generics, it is possible to parameterize the expression type by the type of the expression. For example, Exp<Integer> is an expression that returns an integer, while Exp<Pair<Integer, Integer>> is an expression that returns a pair of integers. Example 9.4 demonstrates the Interpreter pattern with generics. It begins by defining a class Pair<A, B>, with a constructor and two methods to select the left and right components of a pair. It then declares an abstract class, Exp<A>, for an expression that returns a value of type A, with an abstract method eval that returns a value of type A. In our example, there are five kinds of expression:
An interpreter with generics
There are five static methods corresponding to five kinds of expression, each returning an instance of an appropriate subclass of the expression class, with an appropriate definition of the eval method. Finally, the main method constructs and evaluates a sample expression. Generics in Java were inspired by similar features in functional languages such as ML and Haskell. The generic Interpreter pattern is interesting because it shows a way in which generics in Java are more powerful than generics in these other languages. It is not possible to implement this pattern in the standard versions of ML and Haskell, although a recent version of Haskell includes an experimental feature, generalized abstract data types, designed specifically to support this pattern. |