MCS-287 Notes for 2006-03-07

The visitor pattern, even when simplified using multimethods, may not be the most direct approach to adding operations (such as evaluation and conversion) to classes (such as those for sums, products, and constants).

Wouldn't it be nice to stick with the simple idea that such operations are methods of the classes? Recall that in the basic object-oriented composite pattern, we had classes within the Expr class hierarchy that had methods within them such as the following:

    public int evaluate(){
        return left.evaluate() + right.evaluate();
    }

The idea of open classes is to stick with simple methods such as this, but to allow all the various evaluate methods to be packaged together in a single compilation unit which can be added on separately, rather than dispersing the methods within the code of the classes.

In MultiJava, this can be achieved by having, for example, an Evaluation.java file that contains the following four method definitions, each of which augments a different class:

public int Expr.evaluate(){
  throw new Error("Unknown type of Expr: " + this);
}

public int Constant.evaluate(){
  return getValue();
}

public int Sum.evaluate(){
  return getLeft().evaluate() + getRight().evaluate();
}

public int Product.evaluate(){
  return getLeft().evaluate() * getRight().evaluate();
}

One interesting note is that these externally introduced methods need to use the public accessor methods such as getValue and getLeft rather than having direct access to the private instance variables such as value and left. That is, the private/public distinction is defined in terms of compilation units, not classes. A method introduced into a class from a separate compilation unit does not have access to private members of the class.

Essentially the same approach can be used in AspectJ, where the introduction of methods to open classes is treated as a special case of the broader notion of Aspect Oriented Programming, a topic we will discuss at the end of the semester. In AspectJ, the three method definitions would be written as shown above, but wrapped in an aspect definition. Additionally, rather than the Expr class needing a concrete method that throws an Error, the method can be abstract:

public aspect Evaluation {
  public abstract int Expr.evaluate();

  public int Constant.evaluate(){
    return getValue();
  }

  public int Sum.evaluate(){
    return getLeft().evaluate() + getRight().evaluate();
  }

  public int Product.evaluate(){
    return getLeft().evaluate() * getRight().evaluate();
  }
}

I haven't been able to get the MultiJava compiler to work on my system yet, but I can definitely demo this approach in class using AspectJ. We could then either look at adding an additional aspect or additional type of AST node using this approach, or using the Visitor pattern in standard Java, or some mixture.


Course web site: http://www.gustavus.edu/+max/courses/S2006/MCS-287/
Instructor: Max Hailperin <max@gustavus.edu>