CSE 331: Section 5 — Exceptions + Subtyping
Task 1 - A Square and a Rectangle Walk Into a bar()...
Consider the following classes.
public class Rectangle {
private int width;
private int height;
public int getWidth() { ... }
public int getHeight() { ... }
// @effects this.width = w
public void setWidth(int w) { ... }
// @effects this.height = h
public void setHeight(int h) { ... }
}
public class Square {
private int side;
public int getWidth() { ... }
public int getHeight() { ... }
// @effects this.side = w
public void setWidth(int w) { ... }
// @effects this.side = h
public void setHeight(int h) { ... }
}
public class ImmutableRectangle {
private int width;
private int height;
public int getWidth() { ... }
public int getHeight() { ... }
}
public class ImmutableSquare {
private int side;
public int getWidth() { ... }
public int getHeight() { ... }
}
For each comparison below, answer Yes or No and briefly justify your answer.
| Comparison | Yes / No |
|---|---|
Is Square a behavioral subtype of Rectangle? | |
| Why or why not? | |
Is Rectangle a behavioral subtype of ImmutableRectangle? | |
| Why or why not? | |
Is ImmutableSquare a behavioral subtype of ImmutableRectangle? | |
| Why or why not? | |
Is ImmutableRectangle a behavioral subtype of Rectangle? | |
| Why or why not? | |
Task 2 - Try and Catch Me
What if we added a new command?
/*
* s swaps the top two numbers
*/
static void step(CalcStack stack, String token) {
⋮
} else if (token.equals("s")) {
int a = stack.pop();
int b = stack.pop();
stack.push(a);
stack.push(b);
}
⋮
}
-
Assume stack starts empty. What happens when we run
6 s p? -
Which method spec was violated by which method?
-
How could you repair the swap behavior?
Task 3 - Don’t Take It Parse-onally
-
Why does
parsecatch one exception only to throw another? What does this accomplish and how does it affectmain? -
What if
parsedid not catch? What would happen inmain? Consider if we ranabc.static int parse(String token) { return Integer.parseInt(token); } -
What if we broadened what was caught in
main?try { step(stack, token); } catch (Exception e) { System.out.println("error: " + e.getMessage()); }
Task 4 - Testing Coverage Review
-
If we write a test that never reaches a for/while loop conditional, does this count as zero loop iterations?
-
What if the spec does not allow inputs such that we can write a test that covers 0 iterations of the loop?
-
Consider the following method:
/** * Replaces duplicate elements in an array with 0. * * @requires arr != null and every element in arr is positive. * @modifies arr * @effects For every index i, if arr[i] originally appeared at * an earlier index, then arr[i] is replaced with 0. Otherwise, * arr[i] remains unchanged. For either case, the array's * length does not change. */ public static void removeDuplicates(int[] arr) { for (int i = 0; i < arr.length; i++) { boolean duplicate = false; for (int j = 0; j < i; j++) { if (arr[i] == arr[j]) { duplicate = true; break; } } if (duplicate) { arr[i] = 0; } } }Use the testing heuristics from lecture to write a test suite for the following method:
Task 5 - Proofs, Proofs, and More Proofs
-
Explain how P implies Q.
{{ P: exp > 0 and base > 1 and temp = base^(exp - 1) }} {{ Q: base * temp > 1 }} -
Explain how P implies Q.
{{ P: 0 <= count_0 <= capacity and requested >= 0 and 0 <= added <= requested and this.count = count_0 + added and this.count <= capacity and remaining = requested - added and (remaining = 0 or this.count = capacity) }} {{ Q: added = min(requested, capacity - count_0) and this.count <= capacity }}
Calculator Reference
/*
* Commands:
* a number push it onto the stack
* + pop two numbers, push their sum
* - pop two numbers, push (second - first)
* * pop two numbers, push their product
* / pop two numbers, push (second / first), int div
* p print the whole stack
* . pop the top number and print it
* t print the top number without removing it
* q quit
*/
import java.util.Scanner;
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
CalcStack stack = new ListStack();
while (true) {
System.out.print("> ");
if (!in.hasNextLine()) {
break;
}
String line = in.nextLine();
for (String token : line.split("\\s+")) {
if (token.equals("")) {
continue;
} else if (token.equals("q")) {
return;
}
try {
step(stack, token);
} catch (CalcStack.CalcException e) {
System.out.println("error: " + e.getMessage());
}
}
}
}
/**
* Carries out one command.
* @modifies stack, System.out
* @effects carries out the command token stands for, as the class
* comment lists them, printing what the command prints
* @throws CalcStack.CalcException if the command cannot be carried
* out, with a message for the user, and leaves the stack unchanged
*/
static void step(CalcStack stack, String token) {
if (token.equals("p")) {
System.out.println(stack.numbers());
} else if (token.equals(".")) {
System.out.println(stack.pop());
} else if (token.equals("t")) {
System.out.println(stack.top());
} else if (token.equals("+")) {
stack.add();
} else if (token.equals("-")) {
stack.subtract();
} else if (token.equals("*")) {
stack.multiply();
} else if (token.equals("/")) {
stack.divide();
} else {
stack.push(parse(token));
}
}
/**
* @return the integer that token spells
* @throws CalcStack.CalcException if token does not spell an
* integer
*/
static int parse(String token) {
try {
return Integer.parseInt(token);
} catch (NumberFormatException e) {
throw new CalcStack.CalcException(
"don't understand '" + token + "'");
}
}
public interface CalcStack {
/**
* @modifies this
* @effects pushes value onto the top of the stack
*/
void push(int value);
/**
* @modifies this
* @effects removes the top number from the stack
* @return the number removed
* @throws StackEmptyException if the stack is empty, and leaves
* the stack unchanged
*/
int pop();
/**
* A command the calculator cannot carry out.
*/
public class CalcException extends RuntimeException {
public CalcException(String message) {
super(message);
}
}
/** A pop on an empty stack. */
public class StackEmptyException extends CalcException {
public StackEmptyException(String message) {
super(message);
}
}
/** An operation on a stack with fewer than two numbers. */
public class TooFewOperandsException extends CalcException {
public TooFewOperandsException(String message) {
super(message);
}
}
/** A divide whose divisor, the top number, is zero. */
public class DivideByZeroException extends CalcException {
public DivideByZeroException(String message) {
super(message);
}
}
}