# CS334: HW 6

#### Table Of Contents

## Instructions

This homework has three types of problems:

**Self Check:**You are strongly encouraged to think about and work through these questions, but you will not submit answers to them.**Problems:**You will turn in answers to these questions.**Programming:**We’ll do this in the conferences this week. More details then.

## Reading

**(Required)**Read Mitchell, Chapter 8.1—8.2.**(Required)**Read Mitchell, Chapter 9.1—9.2.**(Required)**Mitchell, Chapter 10.

## Problems

### 1. Exceptions (10 points)

Consider the following functions, written in

`ML`

:`exception Excpt of int; fun twice(f,x) = f(f(x)) handle Excpt(x) => x; fun pred(x) = if x = 0 then raise Excpt(x) else x-1; fun dumb(x) = raise Excpt(x); fun smart(x) = (1 + pred(x)) handle Excpt(x) => 1;`

What is the result of evaluating each of the following expressions?

`twice(pred,1);`

`twice(dumb,1);`

`twice(smart,0);`

In each case, be sure to describe which exception gets raised and where.

### 2. Equivalence of Abstract Data Types (15 points)

*Mitchell, Problem 9.2*

### 3. Expression Objects (15 points)

We now look at an object-oriented way of representing arithmetic expressions given by the grammar \[\begin{array}{lll}
e & ::= & \mathit{num} \;|\; e + e \\
\end{array}\] We begin with an “abstract class” called `SimpleExpr`

. While this class has no instances, it lists the operations common to all instances of this class or subclasses. In this case, it is just a single method to return the value of the expression.

```
abstract class SimpleExpr {
abstract int eval();
}
```

Since the grammar gives two cases, we have two subclasses of `SimpleExpr`

, one for numbers and one for sums.

```
class Number extends SimpleExpr {
int n;
public Number(int n) { this.n = n; }
int eval() { return n; }
}
class Sum extends SimpleExpr {
SimplExpr left, right;public Sum(SimpleExpr left, SimpleExpr right) {
this.left = left;
this.right = right;
}int eval() { return left.eval() + right.eval(); }
}
```

##### Questions

*Product Class:*Extend this class hierarchy by writing a`Times`

class to represent product expressions of the form \[\begin{array}{lll} e & ::= & \ldots \;|\; e * e \end{array}\]*Method Calls*: Suppose we construct a compound expression by`new Number(3); SimpleExpr a = new Number(5); SimpleExpr b = new Number(7); SimpleExpr c = new Sum(a,b); SimpleExpr d = new Times(d,c); SimpleExpr e =`

and send the message

`eval`

to`e`

. Explain the sequence of calls that are used to compute the value of this expression:`e.eval()`

. What value is returned?*Comparison to “Type Case” constructs*: Let’s compare this programming technique to the expression representation used in ML, in which we declared a datatype and defined functions on that datatype by pattern matching. The following`eval`

function is one form of a “type case” operation, in which the program inspects the actual tag (or type) of a value being manipulated and executes different code for the different cases:`datatype MLExpr = of int Number of MLExpr * MLExpr; | Sum fun eval (Number(x)) = x | eval (Sum(e1,e2)) = eval(e1) + eval(e2);`

This idiom also comes up in class hierarchies or collections of structures where the programmer has included a

*Tag*field in each definition that encodes the actual type of an object.Discuss, from the point of view of someone maintaining and modifying code, the differences between adding the

`Times`

class to the object-oriented version and adding a`Times`

constructor to the`MLExpr`

datatype. In particular, what do you need to add/change in each of the programs. Generalize your observation to programs containing several operations over the arithmetic expressions, and not just`eval`

.Discuss the differences between adding a new operation, such as

`toString`

, to each way of representing expressions. Assume you have already added the product representation so that there is more than one class with a nontrivial`eval`

method.

## Programming

### 1. Exceptions in ML (10 points)

Your GitLab account will have a project for your to use for this and the following programming questions. You can follow the same instructions as on HW 1 for cloning it and adding a partner.

The function `stringToNum`

defined below uses two auxiliary functions to convert a string of digits into a non-negative integer.

```
(* Convert one character to a numeric digit. *)
fun charToNum c = ord c - ord #"0";
fun calcList (nil,n) = n
| calcList (fst::rest,n) = 10 * n + charToNum fst);
calcList(rest,
(* Convert a string of digits to a number. The explode function
converts a string to a list of characters. *)
fun stringToNum s = calcList(explode s, 0);
```

For instance, `stringToNum "3405"`

returns the integer 3405. (The function `explode`

converts a string into a list of characters, and `ord`

returns the ASCII integer value for a character.)

Unfortunately, `calcList`

returns a spurious result if the string contains any non-digits. For instance, `stringToNum "3a05"`

returns 7905, while `stringToNum " 405"`

returns ~15595. This occurs because `charToNum`

will convert any character, not just digits. We can attempt to fix this by having `charToNum`

raise an exception if it is applied to a non-digit.

Revise the definition of

`charToNum`

to raise an exception, and then modify the function`stringToNum`

so that it handles the exception, returning ~1 if there is a non-digit in the string. You should make no changes to`calcList`

.Implement ML functions to provide the same behavior (including returning ~1 if the string includes a non-digit) as in the first part, but without using exceptions. While you may change any function, try to preserve as much of the structure of the original program as possible.

Which implementation do you prefer? Why? Answer this as a comment in the code.

### 2. Tail Recursion (15 points)

Will do in conferences.

### 3. Visitor Design Pattern (20 points)

The code for this question is located in the `ExprVisitor.java`

file. Include answers to the questions below as comments at the top of that file.

The extension and maintenance of an object hierarchy can be greatly simplified (or greatly complicated) by design decisions made early in the life of the hierarchy. This question explores various design possibilities for an object hierarchy (like the one above) that represents arithmetic expressions.

The designers of the hierarchy have already decided to structure it as shown below, with a base class

`Expr`

and derived classes`Number, Sum, Times`

, and so on. They are now contemplating how to implement various operations on Expressions, such as printing the expression in parenthesized form or evaluating the expression. They are asking you, a freshly-minted language expert, to help.The obvious way of implementing such operations is by adding a method to each class for each operation. This version is not in the starter code, but the expression hierarchy would look like the following in this scenario:

`abstract class Expr { public abstract String toString(); public abstract int eval(); } class Number extends Expr { int n; public Number(int n) { this.n = n; } public String toString() { ... } public int eval() { ... } } class Sum extends Expr { Expr left, right; public Sum(Expr left, Expr right) { this.left = left; this.right = right; }public String toString() { ... } public int eval() { ... } }`

Suppose there are \(n\) subclasses of

`Expr`

altogether, each similar to`Number`

and`Sum`

shown here.How many classes would have to be added or changed to add a new class to represent division expressions.

How many classes would have to be added or changed to add a new operation to graphically draw the expression parse tree.

Another way of implementing expression classes and operations uses a pattern called the Visitor Design Pattern. In this pattern, each operation is represented by a

`Visitor`

class. Each Visitor class has a`visitClass`

method for each expression class*Class*in the hierarchy. Each expression class*Class*is set up to call the`visitClass`

method to perform the operation for that particular class. In particular, each class in the expression hierarchy has an`accept`

method which accepts a`Visitor`

as an argument and "allows the Visitor to visit the class and perform its operation." The expression class does not need to know what operation the visitor is performing.If you write a Visitor class

`ToString`

to construct a string representation of an expression tree, it would be used as follows:`some code that builds the expression tree...; Expr expTree = ...new ToString(); ToString printer = String stringRep = expTree.accept(printer); System.out.println(stringRep);`

The first line defines an expression, the second defines an instance of your

`ToString`

class, and the third passes your visitor object to the`accept`

method of the expression object.The expression class hierarchy using the Visitor Design Pattern has the following form, with an

`accept`

method in each class and possibly other methods. Since different kinds of visitors return different types of values, the accept method is parameterized by the type that the visitor computes for each expression tree:`abstract class Expr { abstract <T> T accept(Visitor<T> v); } class Number extends Expr { int n; public Number(int n) { this.n = n; } public <T> T accept(Visitor<T> v) { return v.visitNumber(this.n); } } class Sum extends Expr { Expr left, right; public Sum(Expr left, Expr right) { this.left = left; this.right = right; } public <T> T accept(Visitor<T> v) { accept(v); T leftVal = left.accept(v); T rightVal = right.return v.visitSum(leftVal, rightVal); } }`

The associated

`Visitor`

abstract class, naming the methods that must be included in each visitor, and the`ToString`

visitor, have this form:`abstract class Visitor<T> { abstract T visitNumber(int n); abstract T visitSum(T left, T right); } class ToString extends Visitor<String> { public String visitNumber(int n) { return "" + n; }public String visitSum(String left, String right) { return "(" + left + " + " + right + ")"; } }`

Here is an example of using the visitor to evaluate and print an expression.

`class ExprVisitor { public static void main(String s[]) { new Sum(new Number(3), new Number(2)); Expr e = new ToString(); ToString printer = String stringRep = e.accept(printer); System.out.print(stringRep); } }`

Starting with the call to

`e.accept(printer)`

, what is the sequence of method calls that will occur while building the string for the expression tree`e`

?Add the following classes to the source file. You will need to change some of the existing classes to accomodate them:

An

`Eval`

visitor class that computes the value of an expression tree. The visit methods should return an`Integer`

. Recall that Java 1.5 has auto-boxing, so it can convert`int`

values to`Integer`

objects and vice-versa, as needed.`Subtract`

and`Times`

classes to represent subtraction and product expressions.A

`Compile`

visitor class that returns a sequence of stack-based instructions to evaluate the expression. You may use the following stack instructions (Refer back to HW 3 if you need a refresher on how these instructions operate):`PUSH(n) ADD MULT SUB DIV SWAP`

The visit methods can simply return a

`String`

containing the sequence of instructions. For example, compiling \(3*(1-2)\) should return the string`PUSH(3) PUSH(1) PUSH(2) SUB MULT`

The instruction sequence should just leave the result of computing the expression on the top of the stack. Hint: the order of instructions you need to generate is exactly a post-order traversal of the expression tree.

Aside: Most modern compilers (including the Sun Java compiler) are implemented using the Visitor Pattern. The compilation process is really just a sequence of visit operations over the abstract syntax tree. Common steps include visitors 1) to resolve the declaration to which each variable access refers; 2) to perform type checking; 3) to optimize the program; 4) to generate code as above; and so on.

Suppose there are \(n\) subclasses of

`Expr`

, and \(m\) subclasses of`Visitor`

. How many classes would have to be added or changed to add a new class to represent division expressions.Suppose there are \(n\) subclasses of

`Expr`

, and \(m\) subclasses of`Visitor`

. How many classes would have to be added or changed to add a new operation to graphically draw the expression parse tree.The designers want your advice. Under what circumstances would you recommend using the standard design?

Under what circumstances would you recommend using the Visitor Design Pattern?

## What To Turn In

#### Problems

Your submitted homework should:

- be clearly written or typed,
- include your name and HW number at the top,
- list any students with whom you discussed the problems,
- be a single PDF file, with one problem per page, and
- be submitted to Gradescope by the due date.

#### Programming

Your submitted programs should:

- be readonably documented and tested,
- list any students with whom you discussed the programming,
- be committed and pushed to your GitLab repository by the due date, and
- be submitted to Gradescope by the due date.

To submit your code in Gradescope, navigate to the submission page for this assignment’s programming component, and select the option to submit files. Then select and upload your source files. If you worked with a partner, only one of you should submit your code, and please indicate who your partner is when you upload your files.

*Note:* The shared repository you are using is either your own or your partners. The other one will be unused. There is no need to do anything to that repository. Our submission scripts will ignore unused repositories and look only at the onces with completed solutions.