You are on page 1of 40

Lecture 1 : Introduction to Textbooks Software is required

Programming in Java No textbook is required. http://www.doc.ic.ac.uk/kenya/


For programming beginners: download Java onto your home machine
Java Software Solutions: Foundations of Program
Lecturer : Susan Eisenbach Design, John Lewis and William Loftus, follow the instructions to install it
Publisher: Addison Wesley, 2002.
This is the 1st lecture on Java then follow the instructions to install
programming.This course is primarily
For experienced programmers: either Kenya or KenyaEclipse
about writing imperative programs using – Learning the Java™ Language at
http://java.sun.com/docs/books/tutorial/
the Kenya system.
– Thinking in Java, Bruce Eckel, Prentice Hall
Next term you will learn to write object
oriented Java programs.
Susan Eisenbach 1 2 3

Functional versus
imperative languages A statement written in Java print() and println()
Functional languages are ideal for expressing the println("Write this in Haskell!");
functional (the problem to be solved) component of any Text can be printed on the screen using
problem however... print() or println().
at least 50% of all programs deal with input/output Commented version
rather than a problem and functional languages aren’t /* Susan Eisenbach
Using println(" ") puts a carriage
very good at input/output.
every statement is
return on the end of the line.
Think of the programs you use now:
* 12 November 2007 print( "7*3" );
editor * a bit of bravado terminated with a ;
println( "=" ); println( 7 * 3 );
mail
language translator (Haskell or Java)
*/ This code prints:
web browser String exclaim = "Write this in Haskell!"; 7*3=
Functional programming should have taught you to println(exclaim); 21
appreciate concise elegant programs.
4 5 6
Concatenating output with + Comments A function written in Haskell
String drink = "slammers"; There are two ways of commenting code. bigger :: Int -> Int -> Int
print("I like "); println(drink); // comments are terminated by the end of line -- post: returns the larger of two numbers
argument types
This code prints: I like slammers // Susan Eisenbach bigger a b|a>b = a
// 12 November 2007 |otherwise = b
println("I like Tequila " + drink); // a bit of bravado arguments
This code prints: I like Tequila slammers /* comments in Java are also terminated by */ Same method written in Java
println /* Susan Eisenbach
int bigger(int a, int b){
("6/9 = " + 6/9 + " or " + 6.0/9.0); * 12 November 2007
//post: returns the larger of the 2 values
* a bit of bravado
This code prints: */ good to make several
if (a > b) {return a;}
6/9 = 0 or 0.6666666666666666 else {return b;}
lines of comments stand
}
out in your program
7 8 9

Returning from a method and


A function written in Haskell A function written in Haskell conditionals
bigger :: Int -> Int -> Int bigger :: Int -> Int -> Int int bigger(int a, int b){
-- post: returns the larger of two numbers -- post: returns the larger of two numbers
//post: returns the larger of the 2 values
bigger a b|a>b = a bigger a b|a>b = a
result type predicate (test) must be in brackets()
|otherwise = b |otherwise = b results have
then and else if (a > b) {return a;}
branches are to be returned
Same method written in Java Same method written in Java surrounded by { } else {return b;} using the keyword
return
int bigger(int a, int b){ int bigger(int a, int b){ }
//post: returns the larger of the 2 values //post: returns the larger of the 2 values
if (a > b) {return a;} if (a > b) {return a;}
else {return b;} else {return b;} conditionals - using the keywords if and optionally else
method bodies are
} } surrounded by { }
10 11 12
A Java program must contain a
/*Susan Eisenbach
*12 November 2007
A function written in Haskell main method *chooses the largest of 3 numbers
*/
void main(){
biggest :: Int -> Int -> Int -> Int It is the main method that starts the execution print("Type in your 3 numbers -> ");
-- post: returns the largest of 3 numbers of a program off. println(biggest(readInt(),readInt(),readInt()));

It doesn’t return anything. The return type of a


biggest a b c = bigger a (bigger b c) }

method that does not return anything is void.


int bigger(int a, int b){
//post: returns the larger of the 2 values
Same function written in Java The first statement can be made into a program if (a > b) {return a;}
as follows: else {return b;}
}
void main(){ int biggest(int a, int b, int c){
int biggest(int a, int b, int c){
println("Write this in Haskell!"); //post: returns the largest of the 3 values
//post: returns the largest of the 3 values return bigger(a, bigger(b,c));
} }
return bigger(a, bigger(b,c));
By custom the main method is the first method in
}
13 the program. 14 15

Assignment - don't use too many


Variable declarations The assignment statement variables
Variables are names of storage locations. Variables can be Initialisation is a form of assignment. superfluous to requirements
declared of the following types:
Assignment gives a variable (named storage
Poor style Better style
int double boolean char String
They must be declared before they are used. location) a value.
int j;
variables can have their values changed int i = 6; int i =6;
throughout a program.
double cost;
String firstname; String surname; int j = 5; int j = 5;
Variables can be initialised in declarations total = total + 1; int k; println(i+j);
int total = 0; total = total / 2;
char answer = 'y'; k = i+j;
double start = 0; answer = 'n';
double sum = 0.0;
Haskell does not have such a low level feature. println(k);
boolean finish = false;

16 17 18
Summary Revision from Haskell
The syntax of the Java programming language Define the base case(s)
is introduced in this course for coding
solutions to the problems set. Define the recursive case(s)
We have seen Lecture 2: Recursion – Split the problem into subproblems
– methods (Haskell functions) with { } – Solve the subproblems
– statement terminators - ; – Combine the results to give required answer
– variables Lecturer : Susan Eisenbach
– conditionals – if (predicate) {…} else {…}
For extra material read parts of
– assignments
– input/output chapters 1,3 and 11
– main method of
– complete Java program
Java Software Solutions
19 Susan Eisenbach 20 21

Haskell program -> Java method becomes: What does assert do?
divisor :: Int -> Int -> Int int divisor (int a, int b){ assert (a > 0 && b > 0):
--pre: the arguments are both assert (a > 0 && b > 0): "divisor must be given arguments > 0";
"divisor must be given arguments > 0";
-- integers > 0
//post: returns the gcd of a and b
--post: returns the greatest common divisor if (a == b) {return a;} evaluates the predicate
divisor a b | a==b = a else {if (a > b) {return divisor (b, a - b);} true? – continue to execute the code
| a>b = divisor b (a-b) else {return divisor (a, b - a);}} false? – print the string on the screen and
| a<b = divisor a (b-a) } stop the program
Do not execute code which you know may crash or loop
forever.
22 23 24
When should you have an assertion? Haskell program -> Java method Java method -> Java program
void main(){
If you write a method that expects something special fact :: Int -> Int
print("Factorial number that you want? ");
of its inputs then you need to put as a precondition --pre: n>= 0
println("Answer = " + fact(readInt()));
whatever needs to be true before the code can be run. --post: returns n!
}
The precondition should be coded (if possible) as an fact 0 = 1
int fact( int n ){
assertion. fact (n+1) = (n+1)* fact n
assert (n>= 0):
becomes :
Assertions can also be written without the String "factorial must be given an argument >= 0";
message. In this case, if the assertion fails then your
int fact( int n ){
//post: returns n!
program stops with an AssertionError.
assert (n>= 0 && n < 17):
if (n==0) {return 1;}
"factorial must be given an argument >= 0";
If the user has given a method arguments that meet //post: returns n!
else {return n*fact(n-1);}
the precondition and the code is correct then the if (n==0) {return 1;}
}
postcondition to the method will hold. Postconditions else {return n*fact(n-1);} Rewrite this program with a more efficient fact
are written as comments at the top of the method } method.
after the word post.
25 26 27

Methods Menu method processMenu method


void processMenu(int reply){
Haskell has functions that return results. void menu(){ assert (0<= reply && reply <=4); curly brackets are
Java has methods that return results (just like //post: 5 lines of text appear on the screen switch (reply){ used for each case
Haskell) case 0: {println("Bye"); break;}
println( "Enter 0 to quit" );
Java has methods that don't return any values, case 1: {println(readInt()+readInt()); break;}
they just execute some code.
println( "Enter 1 to add" ); case 2: {}
– their return type is void. println( "Enter 2 to subtract" ); case 3: {}
– they frequently consume input and/or produce println( "Enter 3 to multiply" ); case 4: {println(" not yet implemented"); break;}
output default: {println("not possible!");}
– The special main method must be void.
println( "Enter 4 to divide" );
}
Both types of methods can be recursive. } }
Java programs can never be recursive.
28 29 30
int used to choose the case to
switch execute, chars can also be used Question Input
switch (reply){
Rewrite processMenu changing it in two ways. There are a huge number of ways of reading
case 0: {println("Bye"); break;}
– remove the precondition input into Java programs.
case 1: {a = readInt(); b = readInt();
– produce the correct answer on the screen for each Whitespace means what you get when you hit
println(a+b); break;}
break prevents cases of the operations the space bar or the enter keys.
case 2:{} Notes
falling through We are using the Kenya system which contains:
case 3:{} – only read in the numbers once
– readInt() –ignores whitespaces, stops after the last digit
case 4: {println(" not yet implemented"); break;} – you can put ifs and switches inside each other or – readDouble() –ignores whitespaces, stops after the last
default:{println("not possible!");} themselves digit
} – tell the user there is an error if reply < 0 or – readString() –ignores whitespaces, stops on the first
} reply > 4 whitespace after the string
– readChar()–ignores whitespace, then reads one character
if integer does not match any case -- not required
– read() – reads the next character (even if it is whitespace)
31 32 readSomething() consumes the carriage return33
character.

Developing a Java program to


reverse a string IMPORTANT The program
void main(){
Specification: Guard your recursive calls. print("type in your word to reverse ->");
– The program should accept a line of text and print
it out in reverse order.
Not guarding your recursive calls can reverse();

Remember: lead to infinite recursion. }


void reverse(){
– A program cannot be recursive only a method can. Make sure there is progress towards the //post: reads in a string (terminated by ENTER '\n')
The main program just calls the method reverse terminating condition between // and prints it out in reverse order
reverse: invocations of the recursive routine. char ch;
Read a character //progress- one char closer to CR
If CR not yet reached //guard the recursive call Comment both the guard and the ch = read(); //progress- one char closer to CR
then
reverse
progression. if (ch != '\n') {
reverse();
print Character.
print(ch);
34 35 } 36

}
Program Input cod Output d o c Summary
reverse(); reverse() A routine that calls itself is called recursive.
ch ='c' Methods can be recursive, programs cannot.
Recursive methods that produce a single result are just like
Lecture 3 : Arrays and For Loops
reverse()
void reverse(){
ch='o'
Haskell functions. Lecturer : Susan Eisenbach
char ch; Void methods are used when the same operation is to be
reverse()
performed on different data and the result wanted is
ch = read(); ch='d' output on the screen. For extra material read parts of chapters 3
if (ch != '\n'){ reverse() In order that the repetition may be finite, within every and 6 of Java Software Solutions.
ch='\n' recursive method there must appear a terminating condition
reverse();
print(ch) to guard the recursive call and a progression to This is the 3rd lecture on Java in which arrays
print(ch); print(ch) distinguish one call from another. and for loops are examined.
} Switch statements are used rather than conditionals when
print(ch)
there are several choices based on an integer or character.
} 37 38 Susan Eisenbach 39

Example of an array variable Another example of an array


What is an array? declarations variable declaration
for problems which deal with large quantities of data double[] vec = new double[10]; If we want to store the sentence “Tom
perform the same, operations on the individual items
is not my friend” we would use:

{
elements of an array are all of the same type and
referred to by an index get space to String[] words = new String[5];
arrays can be one or more dimensional hold 10 doubles
its an array
arrays are called vectors and matrices by non-
computing people the name of the array is vec
“Tom”
comparison with Haskell lists “is”
– every element can be accessed with equal ease each element is a double “not”
– multi-dimensional arrays are easy to access “my”
“friend”
40 41 42
Examples of array variable Arrays can be initialised at
declarations declaration Getting the size of an array
To get the size(no. of elements) of an array, you write
arrayname.length
int[][]mat = new int[5][4]; String[] names = {“Bradley","Eisenbach", The length of the array is determined by the number
of values provided between { }.
"Gillies","Field", for example if
"Hodkinson"}; boolean[] answers = {true, false,
double[] vector = {0.1, 1.2, 0.0, 34.6, true, true, false};
This is an then
-3.0, 34.1, 0.0,
array of arrays answers.length is 5
0.4, 0.8, 0.1}; Note that length is not a method and so does not
have ( ). It is built into Java.
Once created, the size of the array cannot change.
43 44 The length of the array must be specified when it is 45
created.

Examples of array variable


declarations (cont.) Referencing array elements Using arrays:
How do you declare and initialise a data structure
each array element is referenced by means of the array You can pass arrays as arguments to methods:
identifier followed by an index expression which uniquely
for the following? void printNames(String[ ][ ] names)
indexes that element
Susan Eisenbach the first element of an array is at 0, the last at length – 1 You can return arrays as results from methods:
Antony John Field example array references: String[ ][ ] copy(String[ ][ ]names)
firstName = fullNames[2][1]; Do not assign complete arrays:
Christopher John Hogger
vec[1] = mat[1][0]+mat[1][1]+mat[1][2]+ secondYears = firstYears
String[ ][ ] fullNames = { mat[1][3]+mat[1][4]; since any change to firstYears will
{"Susan","","Eisenbach"}, happen to secondYears as well (more
later on this).
{"Antony","John","Field"},
if (i==j) {mat[i][j] = 1;}
{“Christopher",“John","Hogger"}
};
else {mat [i][j] = 0;}
46 47 48
on each loop iteration
Bounded iteration Bounded iteration i=i+1 A for loop example
arrays exist in order to hold a large number of elements of the for (int i = lowerbound; i < upperbound; i++) { for loops are ideal for traversing arrays - each iteration of the
same type loop accesses an element of the array
loop body
frequently the same operation is performed on each array value a program to calculate the mean of an array of doubles:
traversing all the elements of an array can be achieved by means } void main(){
of a control construct known as the for loop. Using a for usually 0 first value of i
double[] vec = {1,0,3,0,5,0,7,-2,9,10};
statement is called looping or iteration and causes repetitive println( mean(vec) );
execution
for (int i = lowerbound; i < upperbound ; i++) { for (int i = upperbound-1; i >= lowerbound; i--) { }
double mean(double[ ] v){
loop body loop body //post:returns the average of the elements in v
} } double total = 0;
for (int i = upperbound - 1; i >= lowerbound; i--) { on each loop iteration for (int i =0; i < v.length; i++) {
loop body stops executing the loop when i=i-1
total = total + v[i];
} i hits this value
}
return total/v.length;
49 50 51
}

Tracing the execution of some When trying to understand what some piece of Java When trying to understand what some piece of Java
code does you hand execute all the code working out code does you hand execute all the code working out
code what the values of the variables are: what the values of the variables are:
mean total i v[0] v[1] v[2] v[3] v[4] void main(){ mean total i v[0] v[1] v[2] v[3] v[4]
void main(){ 1 0 3 1 5 double[] vec = {1,0,3,1,5}; 1 0 3 1 5
double[] vec = {1,0,3,1,5}; println( mean(vec) );
When trying to understand what some println( mean(vec) ); } 0
piece of Haskell code does, you use }
double mean(double[] v){
double mean(double[] v){
int i;
1 0
rewrites: int i; double total = 0.0;
1 1
4 2
fact 4 = 4*fact 3 = 4*3*fact 2 =
double total = 0.0; for (int i =0;i<v.length;i++)
for (int i =0;i<v.length;i++) { 5 3
4*3*2*fact 1 = 4*3*2*1= 24 { total = total + v[i];
10 4
total = total + v[i]; };
}; return total/v.length; 5
return total/v.length; } 2
}
52 53 54
What is the value of names.length?
For each i, what is the value of names[i].length?
Nested for loops Summary
a 2-dimensional array requires 2 for loops to traverse
it: void main(){ Arrays are data structures suitable for problems
int sum(int[ ][ ] m){
String[][] students ={
{"BSc", "Homer", "Marge", "Bart", "Lisa", "Maggie"}, dealing with large quantities of identically typed
//post: returns the sum of the elements of m {"MSci", "Moss", "Jen", "Roy"},
{"BEng", "Peter", "Lois", "Meg", "Brian", "Stewie",},
data where similar operations need to be
int theSum = 0; {"MEng", “Harry", "Adam", "Ros", "Malcolm","Zafar","Connie"} performed on every element.
for (int i = 0; i<m.length; i++){ };
for (int j = 0; j<m[i].length; j++){ printNames( students ); Elements of an array are accessible through their
index values. Arrays using a single index are
}
theSum = theSum + m[i][j]; void printNames(String[ ][ ] names){
} for (int i = 0; i < names.length; i++) {
print(names[i][0] + ": "); called vectors, those using n indices are n-
dimensional arrays. A two dimensional array is
} for (int j = 1; j < names[i].length; j++) {
return theSum; print(names[i][j] + " ");
} } really an array of arrays, a 3-dim., an array of
arrays of arrays, etc.
println();
an n-dimensional array requires n for loops to traverse }
}
If int mat[50][100] is passed to sum, what is the
value of m.length? For each i, what is the value of
55 56 57
m[i].length?

Consider a game to play noughts


Summary and crosses
Arrays have a type associated with them: the Assuming that each space on the board can
type of the elements. The index is always a non- have a 'X', an 'O' or a ' ', write an array
negative integer. declaration to hold a board, initialising it all to
Space has to be allocated explicitly for arrays. Lecture 4 : Using Arrays empty.
Either they are initialised with values and then char[ ][ ] board = {{' ',' ',' '},
the right amount of space is allocated or the {' ',' ',' '}, {' ',' ',' '}};
Lecturer : Susan Eisenbach
keyword new is used to specify the allocation of Write a statement that puts a 'X' into the
For extra material read parts of chapters 3 and 6 in
space. Java Software Solutions. middle square
Repetition of the same operation is called This is the 4th lecture in which code is developed that
board[1][1] = 'X';
iteration or looping. A for loop can be used to do uses arrays and parameter passing mechanism is
examined in some detail.
the same operation to every element of an array.
58 Susan Eisenbach 59 60
Write a predicate isFull which returns true iff Write a method initBoard which
there are no empty spaces on the board. returns a new board filled with spaces. Checking for a winner
boolean isFull(char[ ][ ] b){ After each move a check has to be made
for (int r = 0; r < 3; r++){ char[ ][ ] initBoard(){ whether the current player has won.
for (int c = 0; c < 3; c++){
char[ ][ ] b = {{' ',' ',' '}, A player has won if their piece fills one
if (b[r][c] == ' ')
{return false;} {' ',' ',' '}, of the diagonals, one of the rows or one
} of the columns.
} X X O {' ',' ',' '} X X O
return true; O O X }; O O X
}
X X X X
O return b; O

61 } 62 63

Write a predicate isDiagonal that takes as Write a predicate hasFullRow that takes as Write a predicate hasFullCol that takes as
arguments an X or O and a board and returns true iff arguments an X or O and a board and returns true arguments an X or O and a board and returns true
one of the diagonals is filled with the piece. iff one of the rows is filled with the piece. iff one of the columns is filled with the piece.

boolean isDiagonal(char ch, char[ ][ ] b){ X X O boolean hasFullCol(char ch, char[][] b){ X X O
boolean hasFullRow(char ch, char[ ][ ] b){ assert: ch='X' || ch='O';
assert (ch='X' || ch='O'); assert (ch='X' || ch='O'); O O X
O O X boolean found;
return b[0][0]== ch && boolean found; for (int c = 0; c < 3; c++){
X X
O
X X
for (int r = 0; r < 3; r++){ O
b[1][1]== ch && found = true;
b[2][2]== ch || found = true; for (int r = 0; r < 3; r++){
for (int c = 0; c < 3; c++){ found = found && b[r][c] == ch;
b[0][2]== ch && found = found && b[r][c] == ch;
b[1][1]== ch && X X O }
}
if (found) {return true;}
b[2][0]== ch; O if (found) {return true;} }
} } return false;
X
O
return false; }
}
64 65 66
Put them together to produce a How do you get which square
Exercises to do yourself: predicate isWinner the next player wants?
You could (mouse) click on the square on the screen and the
Write the predicate hasFullCol that takes as coordinates could be converted into the appropriate
arguments an X or O and a board and returns boolean isWinner(char ch, char[][] b){
noughts and crosses index.
true iff one of the columns is filled with the assert: ch='X' || ch='O'; This requires very sophisticated input routines.
piece using only one loop. return isDiagonal(ch,b) || Simpler would be to read in from the keyboard chess
notation for the square and then convert it to the
Rewrite the code in the slides with hasFullRow(ch,b) ||
appropriate array indices.
the board as a one dimensional array. hasFullCol(ch,b); So if a user wants the middle square, it is b2 or 2b
How much harder is it to write the X X O } X X X and the bottom lefthand corner is c1 or 1c a X X O
X X O
predicates? O O X O O X
O O X O O O b
X X X X
O O
X X
O
c
67 68 1 2 369

You need to know if the character the Convert the input characters into numbers
user typed in is for a row or a column that can be used for array indices Arguments to methods
Write a predicate IsRow which takes as an We have been passing arguments to methods.
argument a character and returns true iff the Write a method convert that takes a character
argument is an 'a', a 'b' or a 'c'. that is a valid row or column and returns the Java's argument passing is slightly more
appropriate number to use for the row index or restrictive than Haskell's – you can pass
boolean isRow(char c){ column index. So if '2' is passed as an argument anything to a Java method, except another
return 'a' <= c && c <= 'c'; to convert it returns 1. method.
} int convert(char c){ In Java methods, arguments are passed by
Write a predicate IsCol which takes as an assert (isRow(c) || isCol(c)); value. When invoked, the method receives the
argument a character and returns true iff the if (c=='1' || c=='a') {return 0;} value of the variable passed in, creates a local
argument is an '1', a '2' or a '3'. copy, works on it and then discards it when the
boolean isCol(char c){
if (c=='2' || c=='b') {return 1;} method is left.
return '1' <= c && c <= '3';
return 2; This means that a method cannot change the
} 70
}
71
value of its arguments. 72
What happens when you pass a variable to a What happens when you pass a variable to a When a method is called the runtime system of
method and change its value within the method? method and change its value within the method? any language holds method data in a stack
void main(){ void main(){
int a = 1; int a = 1;
a=1 a=1
int b = 2;
int b = 2; println("a & b = " + a + b); b=2 b=2
println("a & b = " + a + b); swap(a,b); println println
swap(a,b); println("after swap " + a + b);
} temp = 1 temp = 1
println("after swap " + a + b); void swap(int a, int b){
} //post: this method does very little a=2 a=2
void swap(int a, int b){ int temp = a;
b=1 pop
push Aa = 21 , b = 12 , temp = 1 b=1
//post: this method does very little a = b;
b = temp; println push println
int temp = a; Aa = 1, b = 2
println("inside swap " + a + b);
a = b; } a & b = 1 2 println println
b = temp; inside swap 2 1
println("inside swap " + a + b); 73 after swap 1 2 74 75
}

Summary Tutorial questions


A predicate is a method that returns a boolean
result. 1. Translate the following Haskell int power(int x, int n){
It is sensible to name predicates starting with is, functions into Java functions. assert (n >= 0);
are, can or some other similar word.
We have developed a variety of methods that are
//post: x^n
power :: Int -> Int -> Int
necessary if one is writing a noughts and crosses -- pre: the second argument is a non-negative if (n==0) {return 1;}
game. integer
else {return x * power(x, n-1);}
In Java methods, arguments are passed by value. -- post: computes first arg to power of second arg
When invoked, the method receives the value of power x n | n==0 = 1 }
the variable passed in, creates a local copy, works | otherwise = x * power x (n-1)
on it and then discards it when the method is left.
This means that a method cannot change the value76 77 78
of its arguments.
int power1(int x, int n){
power1 :: Int -> Int -> Int assert (n > 0);
-- pre: the second arg is a non-negative integer //post: x^n 2. Write a Java function that calculates
-- post: computes first arg to power of second arg if (n==0) {return 1;} factorials using a for loop. In Java you
power1 x n |n==0 = 1 else{ can have for loops that go backwards.
They are of the form:
|n==1 = x
if (n==1) {return x;}
|n `mod` 2 == 0 = z*z
|otherwise
else{
= z*z*x int z = power1 (x, n / 2);
for (i = 10; i > 0; i--) {
where z = power1 x (n `div` 2) if ((n%2) == 0) {return z*z;}
loop body
In Java `div` is / and `mod` is % else {return z*z*x;}
}
}
79
} 80 81
}

Tuples
When you want to group many of the same type of
int fact(int n){ element together in Haskell you use a list, in Java you
assert (n>= 0&& n <17); use an array.
//post: computes n! You access elements in a list through the head and an
int f = 1; Lecture 5 : Classes array by index (position of element).
Sometimes you want to group a few items of (possibly)
for (int i=n; i>0; i--){ different types together.
f = f*i; Lecturer : Susan Eisenbach In Haskell you would use a tuple. The position of the
} For extra material look at chapters 2 and 4 of Java piece of data would tell you what it was.
return f; Software Solutions. In Haskell you wanted to hold an applicant's name
}
This is the 5th lecture in which classes and objects are followed by the A level points of the top 3 A levels you
introduced. might say:
– type Applicant = ([Char], Int, Int, Int)
– and you would know that the name was the first element of an
82 Susan Eisenbach 83 Applicant. 84
In Java there are classes Using variables of type Applicant Draw a diagram to understand
Applicant me;
Classes can be used like tuples, (although they are Applicant you;
class Applicant{
Draw a diagram of an Applicant.
String name;
much more powerful as you will see later in the course) me.name = "Susan"; int grade1; Susan 60 40 0
Classes contain fields and fields are accessed by name me.grade1 = 60; int grade2; name grade1 grade2 grade3
(not position like tuples) me.grade2 = 40; int grade3;
class Applicant{
me.grade3 = 0; } Rewrite the class declaration for Applicant
String name;
Classes can be passed as arguments and returned from methods so the three grades are held in an array. Draw
int grade1;
boolean areSame(Applicant a1, Applicant a2) a diagram of your new class.
int grade2;
int grade3; What is the difference between the two statements? class Applicant{
– println(me.name + (me.grade1 + me.grade2 + Shakil 120 120 120 String name;
} Susan100 0 1 2
me.grade3)); int[] grades =
Classes are types, (like Haskell types). You create the name grades new int[3];
– println(me.name + me.grade1 + me.grade2 +
type with the class declaration and then you need to
}
declare variables of the type you have created. 85 me.grade3); Susan60400 86 87

Back to noughts and crosses –


Example of an array of classes You need to be able to access elements getting the user's input
class Applicant{ How do you access the fifth person's second A level
String name; good style to put result? Read in from the keyboard chess notation for the
int[] grades = new int[3]; class declarations firstYears[4].grades[1] square and then convert it to the appropriate
} at top of program How do you write a method that takes firstYears as an array indices.
void main(){
argument and returns the index to the first student with So if a user wants the middle square, it is b2 or 2b
Applicant[] firstYears = new Applicant[138]; … name "Dimitri" and –1 if there is no Dimitri in
firstYears. and the bottom righthand corner is c3 or 3c
Anita 120 120 120 0 int find(String name, Applicant[] aa){
Bintal 120 120 120 1 for(int i=0; i<aa.length; i++){
a X X O
if (name == aa[i].name) {return i;}
Carl 120 120 100
2
} O O X
b
:
X X
. return -1; O
.
Wing 120 120 120 137 } c
88 89 1 2 390
You need to know if the character the Convert the input characters into numbers Declare a class to hold the
user typed in is for a row or a column that can be used for array indices coordinates of a move
the predicate IsRow which takes as an argument a
character and returns true iff the argument is an the method convert that takes a character that The coordinates need to be integers so they
'a', a 'b' or a 'c' is a valid row or column and returns the can index the board array.
appropriate number to use for the row index or class Coord{
boolean isRow(char c){ column index. So if '2' is passed as an argument int row;
return 'a' <= c && c <= 'c'; to convert it returns 1. int col;
} int convert(char c){ }
the predicate IsCol which takes as an argument a assert (isRow(c) || isCol(c)); Next write a method getMove which reads
character and returns true iff the argument is an from the keyboard the user's input. If it isn't
if (c=='1' || c=='a') {return 0;}
'1', a '2' or a '3' a legal input (forget whether the square is
boolean isCol(char c){
if (c=='2' || c=='b') {return 1;} occupied) then prompt again and read in the
return 2; user's input. Continue this until correct input
return '1' <= c && c <= '3';
} is typed in. The method should return a Coord.
} 91 92 93

Coord getMove(){
Coord move;
getMove in Java
Declare getMove What is the algorithm for getMove? char c1; char c2;
c1 = readChar();
c2 = readChar();

getMove takes no arguments (it reads its c1 = readChar() if (isRow(c1) && isCol(c2)){

c2 = readChar()
move.row = convert(c1);
inputs from the keyboard) and returns a move.col = convert(c2);
Coord. Coord getMove() if isRow(c1) && isCol(c2) return move;
move.row = convert(c1) }
What local variables are needed by getMove? move.col = convert(c2)
else{
-two variables to hold the input characters if (isCol(c1) && isRow(c2)){
return move move.row = convert(c2);
char c1, c2; else if isCol(c1) && isRow(c2) move.col = convert(c1);

move.row = convert(c2)
return move;
-a variable to hold the coordinates of the move to be }
returned move.col = convert(c1) else{

Coord move; return move println("bad coordinates, re-enter-->");

else println("bad coordinates, re-enter-->")


return getMove();
}
94 return getMove() 95 } 96
}
While loops Loops Example of a generalised loop
void main(){
for loops are ideal to use with arrays, where you know while (condition)
char answer = 'y'; char buf = ' ';
exactly the number of iterations. {
showInstructions();
When you want repetition and you don't know in body of loop
advance how many times the repetition will occur you }
while ( answer == 'y‘ || answer == ‘Y’ ){
can use recursion or a while loop construct. playGame();
the body of loop includes something that will make the
It is a matter of taste whether you use while loops or condition go false eventually
print("Do you want to play again(y/n)? ");
recursion when you don't know beforehand how many answer = readChar();
times you need to repeat. A loop where the condition cannot become false is an infinite
loop. The loop below will not stop. buf = readChar() ;
Like recursion generalised loops can go infinite. When }
writing code you must ensure that your code will while (true)
terminate. { println("thanks for playing");
body of loop }
buf is needed to hold the
} Return character which 99
is
97 98
never used, just discarded

Example of a generalised loop meth in ans output method Summary


The rest of the code: main y
void showInstructions(){
To group a few items of (possibly) different types
println("instructions go here"); ShowInstructions instructions go here together a class is used.
} Access is by field name (not position).
void playGame(){ playGame the whole game goes here
println("the whole game goes here"); To access the field f in class C we write C.f
} main y y Do you want to play again(y/n)? y It is good style to place all the class declarations at
¿How would you implement this recursively? the very top of the program before the main
Trace the code with the input y y k. In addition playGame the whole game goes here
method.
to the column for the variable answer have a
y y
column for the methods being executed, a column main Do you want to play again(y/n)? y

for input and a column for output. playGame the whole game goes here
100 101 102
main k k Do you want to play again(y/n)? k
Primitive values Primitive values
ints, doubles, booleans, Strings, and What happens is the bit pattern that is the
chars are primitive. value at the storage location called a is
Java has many other number types that are compared with the bit pattern at the storage
Lecture 6 : Objects also primitive. location called b.
Primitive variables are names for storage If they are identical the value of the
locations that contain the values of the expression is true otherwise it is false.
Lecturer : Susan Eisenbach variables.
For extra material read chapter 4 of Java Software What happens when during the execution of int a = 3;
Solutions.
your program checking the expression a==b int b = 4; 0…0…011 == 0…0…100 ???
This is the 6th lecture in which primitive types and where a and b are both ints is reached?
objects are introduced. The last tutorial question is also a==b?
gone over. a b

Susan Eisenbach 103 104 105

Objects How objects are stored How objects are stored


Arrays and classes are not primitive. They are data Consider the following declarations: What are the values of v1 and v2?
structures and stored as objects.
Objects (of an array or class type) need to have their char[ ] v1 = {'a','a','a','a'}; The two references (or addresses 10000
space explicitly allocated before they can be used. char[ ] v2 = {'a','a','a','a'}; and 11000) to locations in the heap.
For arrays you do this explicitly by using new.
If you look at the Java code for class declarations v1 v2 v1 v2
generated by the Kenya system you will see the word
new. This word means create the object on the heap.
Object variables are names for storage locations that a a a a a a a a
contain a reference or pointer to the data structure. a a a a a a a a
(but in binary) (but in binary)
The actual data structure is stored in a part of address
(but in binary)
address
(but in binary)
memory called the heap. 10000
address heap
10000
address
106 11000 107 11000 108
What gets printed? Why? Take care with = and ==
void main(){ If you wish to assign one object to another
void main(){ char[ ] v1 = {'a','a','a','a'}; then you must do it component at a time.
char[ ] v1 = {'a','a','a','a'};
char[ ] v2 = {'a','a','a','a'};
if (v1 == v2) {println("same");}
Otherwise you will just have 2 names (known as
char[ ] v2 = {'a','a','a','a'}; else {println("different");} aliases) for the same object.
if (v1 == v2) {println("same");} v2 = v1; Instead of writing
v1[0] = 'b';
else {println("different");} me = you;
if (v1 == v2) {println("same v2[0]="+v2[0]);}
v2 = v1;
v1[0] = 'b'; }
else {println("different");} you should write
v1 v2
if (v1 == v2) {println("same v2[0]="+v2[0]);} different me.name = you.name;
else {println("different");} same v2[0]= b me.grade1 = you.grade1 etc. Then you
}
a a a a
b a a a a will have two different objects with the same
values.
different
same v2[0]= b
109 110 111

Java provides arraycopy for Arguments to methods – repeat What happens when you pass a variable to a
copying arrays. of earlier slides (reminder) method and change its value within the method?
void main(){
arraycopy takes source and copies it to We have been passing arguments to methods.
int a = 1;
destination Java's argument passing is slightly more int b = 2;
What gets printed? restrictive than Haskell's – you can pass println("a & b = " + a + b);
int[ ] v1 = {1,1,1,1};
anything to a Java method, except another swap(a,b);
method. println("after swap " + a + b);
int[ ] v2 = {2,2,2,2};
arraycopy(v1,v2); In Java methods, arguments are passed by }

v1[0] = 33; value. When invoked, the method receives the void swap(int a, int b){
for (int i=0; i < v2.length; i++){ value of the variable passed in, creates a local //post: this method does very little
print(v2[i]);
copy, works on it and then discards it when the int temp = a;
method is left. a = b;
}
This means that a method cannot change the b = temp;
1111 112
value of its arguments. 113 println("inside swap " + a + b); 114
}
What happens when you pass a variable to a What happens when you pass an object to What happens when you pass an object to
method and change its value within the method? a method and alter the object? a method and alter the object? 21 12
void main(){
int a = 1;
a=1 void main(){ void main(){
int b = 2; int[ ] p = {1,2}; int[ ] p = {1,2};
println("a & b = " + a + b); b=2 println("p[0] & p[1] = " + p[0] + p[1]); p=
swap(a,b); println println("p[0] & p[1] = " + p[0] + p[1]); swap(p); println
println("after swap " + a + b); swap(p); println("after swap " + p[0] + p[1]);
} temp = 1 temp = 1
println("after swap " + p[0] + p[1]); }
void swap(int a, int b){ void swap(int[ ] p){
//post: this method does very little a=2 } p[0] = 2
int temp = p[0];
int temp = a; void swap(int[ ] p){
b=1 p[0] = p[1]; p[1] = 1
a = b; int temp = p[0];
b = temp; println p[1] = temp; println
println("inside swap " + a + b);
p[0] = p[1]; println("inside swap " + p[0] + p[1]);
} a & b = 1 2 println p[1] = temp; } p[0] & p[1] = 1 2 println
inside swap 2 1 println("inside swap " + p[0] + p[1]); inside swap 2 1
after swap 1 2 115 } 116 after swap 2 1 117

What happens when you pass an object


to a method and alter the object? Details about the heap What does this program print out?
void main(){
What is passed to a method is the address of Both arrays and classes are objects that when created int[ ] p = {10,20};
live in the heap, which is just a special part of
the object.
println("p[0] & p[1] = " + p[0] + " " + p[1]);
computer memory. change1(p);
Like arguments, this is copied and the local Anything that lives in the heap must get allocated println("p[0] & p[1] = " + p[0] + " " + p[1]);
copy is worked on and then discarded, at the some space in the heap before it can be accessed. change2(p);

end. The way an array or class is accessed is via its address println("p[0] & p[1] = " + p[0] + " " + p[1]);
in the heap also called a pointer. }
However the object lives in the heap and there If an object has not been allocated space then the
void change1(int[ ] p){
is no such thing as a local heap. address will be a special one called a Null Pointer.
int[ ] q = {99,999};
p = q;
Any alterations to the heap that happen during If you try to access an object that has not yet been println("inside change1: p[0] & p[1] = "+p[0]+" "+p[1]);
allocated some space then you will get a
the execution of a method are permanent. NullPointerException.
}
void change2(int[ ] p){
A NullPointerException means you tried to access an p[0] = 1000;
object, which did not exist. println("inside change2: p[0] & p[1] = "+p[0]+" "+ p[1]);
118 119 } 120
Answer: Consider an array of classes How do we write Thing[]initThings?
p[0] & p[1] = 10 20 class Thing{ Within initThings we need first to create an array.
int value = 0; Thing[] tt = new Thing[5];
If tt just held integers then each array element would
char answer = 'y';
inside change1: p[0] & p[1] = 99 999
contain a 0.
}
p[0] & p[1] = 10 20 void main(){ But since each array element holds an object it needs
printThings(initThings()); to contain the address of the object.
inside change1: p[0] & p[1] = 1000 20 As none of the objects have yet been given addresses
}
p[0] & p[1] = 1000 20 then each array element contains the special null
void printThings( Thing[] tt){ address which is normally shown with the symbol you
can see below:
Why do you get this output? for (int i = 0; i < tt.length; i++){
println("value = "+tt[i].value+" answer = "+tt[i].answer);
}
}

121 122 123

What happens when you execute one


To initialise every cell in tt iteration of the for loop (say i = 2) The complete program
class Thing{
for (int i = 0; i < tt.length; i++){ int value = 0;
Thing t; char answer = 'y';
}
tt[i] = t; Thing t;
void main(){
} printThings(initThings());
If you check each array element before the }

statement tt[i] = t; has been executed you will tt[2]=t;


see that it contains the value null. Thing[] initThings(){

If you check each element after tt[i] = t; has 0 ‘y’ 0 ‘y’


Thing[] tt = new Thing[5];
for (int i = 0; i < tt.length; i++){
been executed you will see that it has been Thing t; //grabs appropriate space on the heap
initialised. }
tt[i] = t;

Execute the program in step mode and check the 0 ‘y’ return tt;
array values at each for loop iteration. }

void printThings( Thing[] tt){


for (int i = 0; i < tt.length; i++){
println("value = " + tt[i].value + " answer = " + tt[i].answer);
124 125 } 126
}
Kenya has enumerated types like
Summary Haskell
Variables declared as a class or array type are An enumerated type is a type whose legal values consist of a
fixed set of constants.
objects and not primitive. This means they are When the data your program uses is not numeric then using an
actually references to memory addresses in the Lecture 7 : Enumerated Types and enumerated type makes your program more readable and hence
more maintainable
heap. Simulation Haskell:
Tests for equality and assignment have to be data Day =
undertaken subcomponent by subcomponent. Sun|Mon|Tues|Wed|Thurs|Fri|Sat
Lecturer : Susan Eisenbach Kenya:
Arrays can be assigned using arraycopy. For extra material read chapter 3 of Java Software enum Day{
Objects are held on the heap and when changed in a Solutions. SUN,MON,TUES,WED,THURS,FRI,SAT;

method are permanently changed.


}
This is the 7th lecture in which enumeration types are
explained and a simulation program for a vending By convention the constants are all written in upper case.
machine is developed.

127 Susan Eisenbach 128 129

Enumerated types - examples Using an enumerated type The next element


compass directions, which take the You must use the name of the enumerated void main() {
values North, South, East and West type before the value so with declaration Days d = Days.SUN;
days of the week, which take the values enum Day{ while (d != Days.SAT){
Sunday, Monday, Tuesday, Wednesday, SUN,MON,TUES,WED,THURS,FRI,SAT;
println(d);
Thursday, Friday, and Saturday }
d = enumSucc(d);
you write code such as:
suits in a deck of cards }
Day today;
values in a deck of cards today = Day.MON; println(d); This gives the next day
In the list of Days
planets in our solar system println(today); }
Day must prefix
operators for a calculator 130 every value of Day 131 132
Can use enumerated types with for Enumerated types and switch Day does not prefix
loops statements the choices

void main() { One of the most useful things you can do switch ( today ){
for(Days d = Days.SUN; with an enumerated type is use it for a case MON :{}
case TUES :{}
d != null; switch variable. case WED :{}
d = enumSucc(d)) In switch cases, you must remember not case THURS :{work(); break;}
{ Cannot use < or > on to put the type-name as a prefix for the case FRI :{play(); break;}
println(d); an enumerated type,
constants. case SAT :{}
just == and !=. case SUN :{doNothing();}
}
}
}

133 134 135

Without and with the prefix Simulation Vending Machine


Day closestWeekDay( Day d){ Computer programs are regularly written to We will now develop a program to simulate a
simulate something real. vending machine that sells sweets.
switch ( d ){
You have probably all played simulation games Here is the interaction between the machine
case SAT :{return Day.FRI;} (e.g. a computer game of solitaire or a flight and the user
simulator) but simulation is also used to help – Machine: lists sweets with numbers and prices
case SUN :{return Day.MON;} understand some real process that is too – User: inputs number of choice
default : {return d;} difficult to understand any other way – Machine: lists price of chosen item
– User: inputs money
} There is an entire course in the third year for – Machine: gives change (in fewest possible number of coins)
understanding how to write simulation Two simplifications on reality:
} programs called "Simulation and Modelling" – – our vending machine always has all the coins it needs to give
Tony Field and Jeremy Bradley. the appropriate change
136 137 – our users always put in at least enough money 138
First step in implementing: First step in implementing:
Sample Vending Machine Interaction declarations for the data declarations for the data
********** Vending Machine ************** Declare variables to hold the choice, the payment and In order to give the appropriate change in coins, the
*** Choose From the Following *********** the cost. values of each of the coins must be known. Declare and
1: Mars Bars ******** 50 p * int choice; initialise a variable to hold the values of all coins.
2: Polos ******** 36 p * int payment;
3: Mini Skittles ********* 12 p * int[] values = {1,2,5,10,20,50,100,200};
int cost;
4: Crisps ********* 44 p * In order to print out the change, the coin names must
***************************************** In the program the prices of the sweets must be
known. Declare and initialise a variable to hold the be known. Declare and initialise a variable to hold the
Please make your choice 4 names of all the coins.
Please pay in 44 pence, paid in 60 prices of the sweets.
Your change in the fewest possible coins: int[ ] prices = {50,36,12,44}; String[] coinNames = {"one pence", "two pence",
1 one pence "five pence", "ten pence",
1 five pence "twenty pence",
1 ten pence "fifty pence", "one pound",
139 140 "two pounds"}; 141

The hardest problem Declaring coins How do you solve the problem?
Given an amount it will be necessary to convert Write the declaration (header) for a You need to create a local (just in the method)
it into the (fewest) coins needed to make up array money to return from the method
that amount. So we need a method that does
method called coins which takes as containing the different numbers of coins.
the following: arguments the amount (assume it is > 0) You need a local variable whatsLeft that
– 3 {1,1,0,0,0,0,0,0} and the values of the coins. Include your contains the amount you haven't yet put into
– 65 {0,0,1,1,0,1,0,0}
– 48 {1,1,1,0,2,0,0,0} , etc.
pre and post conditions. money.
To do this the array of values is also required, walk over the array values from right to left
int[] coins(int n, int[] values)
since we need to know the value of each of the assert (n > 0); money[i] = whatsLeft / values[i]
coins. //post: the fewest coins whose values sum to whatsLeft = whatsLeft % values[i]
// equal n is returned return money
142 143 144
What if you want to be able to
In Java do the converse of coins? Write the method sum in Java
{ Declare a method sum which takes as an argument an int sum(int[] money, int[] values){
int money = new int [8]; array money which contains the number of each of the //post: the monetary value of m is returned
int whatsLeft = n; coins and which returns the sum of the coins. You will
also need to pass values as an argument in order to
int total = 0;
for (int i = money.length-1; i>=0; i--){
money[i] = whatsLeft / values[i]; calculate the sum. Include any pre or post conditions. for (int i = 0; i<money.length; i++){
whatsLeft = whatsLeft % values[i]; int sum(int[] money, int[] values) total = total + money[i]*values[i];
} //post: the monetary value of m is returned }
return money; What is the algorithm for the body of the method? return total;
} total = 0 }
walk over the array money (from left to right)
total = total + money[i]*values[i]
145
return total 146 147

You need to be able to print out Write the method printMoney


the change in words in Java Finally, the main program
void main(){//all the declarations go here
Declare a method printMoney, which takes an array println(" ********* Vending Machine **************");
with the money to be printed and an array of the void printMoney(int[] m, String[] names){ println(" ******* Choose From the Following ******");
names of the coins and prints on the screen the //post: the names and numbers of the coins println(" 1: Mars Bars ****** 50 p *");
number of each of the coins. // in M are printed on the screen println(" 2: Polos ****** 36 p *");
for (int i = 0; i < m.length; i++){ println(" 3: Mini Skittles ****** 12 p *");
void printMoney(int[] m, String[] names) if (m[i] > 0) {println(m[i] + println(" 4: Crisps ****** 44 p *");
//post: the names and numbers of the coins " " + names[i]);} println(" ****************************************");
// in M are printed on the screen } print("Please make your choice");
choice = readInt();
}
What is the algorithm for the body of the method? cost = prices[choice-1];
print("Please pay in " + cost + " pence, paid in ");
walk over the array money (from left to right) payment = readInt();
if money[i]>0 println money[i] : names[i] println("Your change in the fewest possible coins: ");
printMoney (coins(payment - cost, values), coinNames);
148 149 150
}
Summary Summary
Kenya has enumerated types like Haskell.
enumSucc is used to get to the next value, so they
Lecture 8 : The Design of
An enumerated type is a type whose legal can be used in for loops as counters Algorithms
values consist of a fixed set of constants. One of the most useful things you can do with an
When the data your program uses is not enumerated type is use it for a switch variable (in Lecturer : Susan Eisenbach
numeric then using an enumerated type makes this case without the prefix.
your program more readable and hence more A simulation program for a vending machine was
maintainable. developed.
This is the 8th lecture on Java in which we look at
You must use the name of the enumerated It was developed by first deciding on the data how to design programs.
type before the value. needed and then writing the methods that worked
on the data.
Two values of the same enumerated type can
be compared with == and != .
151 152 Susan Eisenbach 153

Sorting an unknown number of


numbers Sentinel values How do you read in the list?
If you don't want to count the numbers first You need to declare the array at its maximum
In the tutorial question last week you were and there is at least one value that could not size.
asked to sort 10 numbers. be in the list (say if you were sorting non- double[] vector = new double [100];
This is quite a restrictive problem. negative numbers any negative value would do, You need to declare an integer variable to hold
How would you sort any number of numbers otherwise a very large or very small number the actual length of the list, which you get by
(say up to 100)? that wouldn't be in your data for example – counting. int len = 0;
9999) put it at the end. This will have to be passed to the sort method.
Firstly you need to know how many numbers
For example, if you are sorting the numbers You need a boolean variable that is true iff you
you are going to sort. should continue reading numbers.
There are three ways of doing this. You can 1, 6, 4, 0, 7, 8 boolean goOn = true;
type in the number of numbers, followed by The list 1, 6, 4, 0, 7, 8, -1 is entered and the You need a double variable to hold the number
the numbers. These can be processed with a first 6 numbers are sorted. that is read in.
for loop. The value –1 (which mustn't be sorted) is double buf;
154 155 156
called a sentinel value.
Now you need a while loop to Now you need a while loop to
read in the numbers The special End of File character read in the numbers
while (goOn){ When input comes from a file rather than the double[] vector = new double[100];
buf = readDouble(); keyboard after all the input has been
goOn = len < 100 && buf > -1; consumed a system predicate isEOF is set to int len = 0;
true. while (!isEOF() && len < 100){
if (goOn) {
When input comes from the keyboard you can
vector[len] = buf; set this predicate to true in 2 ways
vector[len] = readDouble();
len = len + 1; – by typing in ^Z (pronounced Control Z)(windows) or ^D (linux) len = len + 1;
} – by pressing the EOF button on the rhs of the input panel
This predicate can be used to stop reading in }
}
values.
It is important not to store the sentinel value in
the array
157 158 159

The programming process The programming process The programming process


requirements specification : What should the
programming without much thought only works design : How will the program satisfy these
for small problems program do?
results in a document known as the requirements?
many different schemes exist to systematise – data - information the program manipulates
programming requirements specification or specification
– algorithms - methods to manipulate the data results in the
they encourage programmers of diverse This is written in formal logic and/or concise design documentation or design
abilities and experience to produce programs English. implementation : design is transformed into
of uniform quality I know you believe you understand what you think I said,
we'll use a three-stage process which provides code
but I am not sure you realise – coding - should be routine, results in the "finished product" -
a framework to: that what you heard tangible code
– generate consistent, understandable programs is not what I meant. – testing - does the program perform according to spec?
– allow scope for individual programmers to apply
their own problem-solving skills
Anon
160 161 162
Refining the requirements
Design documentation Specification of a calculator specification
design is an iterative process, progressively Concise verbal statement to start: The program should accept two numbers, separated by an
more detailed decisions are made: The program should accept two numbers, separated by an arithmetic operator, and should produce the correct
– data arithmetic operator, and should produce the correct arithmetic result, if this is calculable.
– algorithms arithmetic result, if this is calculable. Numbers are non-negative whole numbers.
the process of refining the algorithms with Forms the basis of a discussion between Arithmetic operators are +, -, * and /.
detail is known as programmer and client to fill in details. Calculable means that the result must be finite, whole and
– What is a number? non-negative.
stepwise refinement or top down design
– What is an arithmetic operator? Input consists of number operator number return.
documents required:
– What sums are calculable? Input may be separated by spaces and is separated from the
– data declarations - for the data
– pseudo-code or Haskell - for the algorithms – What form should the sum be in? result by a new line.
– What should the program do if the result is not It is assumed that the user types in correct data.
calculable? A potentially incalculable result will produce the error
– How many calculations should the program do? message: "cannot calculate".
163 164 165

Data declarations for the


The data Inputs and outputs calculator
What does a program do? It consumes input inputs are from the keyboard String errorMessage = "cannot calculate";
and produces output. The first stage of design – first
int first;
is to figure out what inputs to the program are char op; //one of: + - * /
– op
and what the outputs from the program are. int sec;
– sec int result;
All inputs and outputs identifiers (names)
need to be declared and defined. outputs are to the screen
Data types are those that are recognised by – result Alternatively op could be an enumerated type:
Java and written in Java. – errorMessage Operator = {PLUS, MINUS, TIMES, DIVIDE}
Operator op;
Comments are written after // . program called calculator
Now all we need to do is define a
calculator //performs simple arithmetic on
166 167
//non-negative integers 168
Extend data declarations to
Pseudo-code Stepwise refinement include Expression
We need a language to write our algorithms in. When writing the algorithm whenever things class Expression{
This could be Java but then you need to worry get complicated make up a name and hive the
about syntax details. complication off to another process to be int first;
Instead we will use a language called pseudo- dealt with later. (Use indents instead of char op; //'+','-','*','/'
code. It has no predefined syntax. brackets and semicolons)
calculator: int sec;
It is close enough to Java to translate
obviously. It is close enough to English that read first, op, sec }
you don't have to worry about fussy details of if the expression is calculable
syntax. then evaluate the expression put the result
Everyone's pseudo-code is slightly different. else put errorMessage
There has already been some pseudo-code 169 170 171
used in this course.

Now define evaluate Now isCalculable Design complete


Turn isCalculable into something that is obviously a For first year programs, the data declarations
evaluate: (extended with anything new that comes out of the
pre IsCalculable predicate - a boolean method pseudo-code) and pseudo-code form the design.
switch on op isCalculable : Before proceeding to write the code, reread the
'+' : result first + sec switch on op specification. Check that the design meets the
'-' : result first - sec specification and change the design if it does not.
'-' : result first >= sec It should be straightforward to turn the design into
'*' : result first * sec
'/' : result sec != 0 code.
'/' : result first / sec
'+', '*' : result true The class, variable and method declarations should
come from the data declarations.
How would you write evaluate in Haskell : result false
The code should come from the pseudo-code. Amend
instead of pseudo-code? or isCalculable: the pseudo-code and data declarations if you decide on
return op == '+' || op == '*' || any changes. Programming is an iterative process and
172 op == '-' && first >= sec || 173
there will be changes. 174

op == '/' && sec != 0


Declarations isCalculable (both versions) Evaluate:
class Expression{ boolean isCalculable (Expression e){ int evaluate (Expression e){)
int first; return e.op == '+' or e.op == '*' || assert (isCalculable(e));
e.op == '-' && e.first >= e.sec || switch (e.op) {
char op; e.op = '/' && e.sec != 0; case '+' : {return e.first + e.sec;}
int sec; } case '-' : {return e.first - e.sec;}
} boolean isCalculable( Expression e ) { case '*' : {return e.first * e.sec;}
switch ( e.op ) { case '/' : {return e.first / e.sec;}
case '-' : {return e.first >= e.sec;} default : {return -1;}
String errorMessage = "cannot calculate"; case '/' : {return e.sec != 0;} }
case '+' : {return true;} }
Expression expr;
case '*' : {return true;}
default : {return false;}
175 } 176 177
}

Finally, the program: Summary Summary(cont.)


void main(){
How a problem should be solved should be tackled
String errorMessage = “cannot calculate”; To be able to solve a problem by computer you must after completely determining what the problem is.
Expression expr ; be able to decide what the problem is and how it How to solve the problem comes next - the design.
expr.first = readInt(); should be solved. The method of stepwise refinement consists of
Java is less abstract than Haskell so programs decomposing a problem into simpler sub-problems.
expr.op = readChar();
This data needs to be decided on as well.
expr.sec = readInt(); written in it must be designed before they are
committed to code. An algorithm describes how the inputs to a
if (isCalculable(expr)) process produce the outputs.
The first step in solving a problem is to understand
{println(evaluate (expr));} Algorithms are described either in Haskell or
what the problem is; this is called the specification
else {println(errorMessage);} pseudo-code.
}
stage.
178 179 180
Altering the previous
Back to the calculator declarations
The data declarations:
The specification of a calculator was too rigid. class Expression{
int first;
Any reasonable calculator program would be
Lecture 9 : Designing Input more flexible about its input. The original
char op; What happened to result?
int sec;
Lecturer : Susan Eisenbach specification said: }
Input consists of number operator number return. String notCalculable = "cannot calculate"
Input may be separated by spaces and is separated String syntaxError = "not an expression"
from the result by a new line. It is assumed that the
This is the 9th lecture on Java in which we look user types in correct data. The program declaration:
at the kinds of difficulties reasonable input calculator //program performs arithmetic on non-negative ints
causes a programmer. More reasonably would have been a The method declarations:
specification that included: evaluate = int evaluate(expression)
If the user fails to type in correct data then an error pre isCalculable
message "not an expression" will be output. isCalculable = boolean isCalculable(expression)

Susan Eisenbach 181 182 183

Pseudo-code Calculator: How do we do input?


readExpression expr=readExpression(); Previously our input was done with the statements:
if the expression isCalculable if isCalculable(expr) expr.first = readInt();
The only change needed in the main program is evaluate the expression
expr.op = readChar();
that instead of using the Java readInt, {println expr.sec = readInt();
print the result If you type in:
readChar and readInt to read in an (evaluate(expr));}
else print notCalculable
expression it should be hived off to its own else
x + 2
method to be sorted out. Pseudo-code isn't {println Could not read integer, incorrectly formatted number (x)
wonderful for such fiddly details so the code
(notCalculable);}
is also provided. All the real work needs You never want your users to see wrong answers or
to be done in messages you didn't write.
readExpression
184 185 186
Converting numeric character How do we convert the character
Why? strings to numbers '5' to the number 5?
Our input routine must be able to deal with receiving readInt() reads in numbers as strings and then All characters have ascii values.
converts what it has to a numeric value.
syntactically incorrect data and outputting the error – '0' is 48
How does it convert "345" into 345? – '1' is 49
message
You process the characters from left to right. – '2' is 50, etc
"not an expression"
string left value of number So the ascii value of ('5') minus the ascii value
readInt terminates on any non-numeric character. "345" 0 of ('0') is equal to
5
Given the input x + 2 readInt reads in the x, the "45" 10*0+3 = 3 You can get the ascii value of a character by
first non-numeric character, rejects it as a number, "5" 10*3 + 4 = 34 assigning it to an integer variable.
and terminates the entire program. "" 10*34 + 5 = 345 So if c is a char, c – 48 will be the value you
34
0
345 want.
3 4 5
Alternatively you can use the Kenya builtin
method charToInt(c).
187 188 189
There is also intToChar(i).

What other builtin methods are in Switches can be used to convert a


Kenya? character to a numeric value. isDigit for the assertion
Check out http://www.doc.ic.ac.uk/kenya/kenya4/ReferenceGuide/ Write a method that takes a character in the range '0' <= Write a predicate (boolean method)
character <= '9' and returns the numeric value, eg '0' 0,
String charsToString(char[] source);
etc. Use a switch statement. isDigit that returns true iff a
void main(){
char[] myChars = { int convert(char c){ character is in the range '0' to '9'.
assert (isDigit(c));
'h','e','l','l','o',‘ ','w','o','r','l','d' };
switch (c) {
String helloWorld = charsToString(myChars); case '0' : {return 0;}
// prints "hello world" case '1' : {return 1;}
case '2' : {return 2;}
println(helloWorld); case '3' : {return 3;}
boolean isDigit(char c){
case '4' : {return 4;} this only works if return '0' <= c && c <= '9'
} case '5'
case '6'
:
:
{return
{return
5;}
6;}
the character is a }
char[] stringToChars(String argument) case '7' : {return 7;} digit
case '8' : {return 8;}
case '9' : {return 9;}
default : {return -1;}
190 } 191 192
}
Buffering input Two ways we can write readExpression: Processing a line at a time
read one character at a time and process it as it arrives
If you wish your program to print out all error read the complete input line into an array of char and then If we wish to process a line at a time then
messages then you have to read in the characters and process it readExpression will need to be rewritten.
convert them into numbers yourself. do not use String, because you cannot process characters readExpression:
To write a calculator which will accept both 31+4 and in it and because readString() will only read up to the
31 + 4 we need to process a character at a time and first space readLine
convert the characters into numbers where you will only know that you have finished a number when you if isValid //number operator number
appropriate. are looking at the character that follows: convert line to expression
– 31 + 4
3 1 + 4 \n 3 1 + 4 \n – 3 5+4 else
in the first example you need to read in the ' ' to know that println syntaxError
{
{
{
{

the number is 31. In the second example you need to read


in the '+' before you know that the number is 35.
readExpression
first number character terminating readLine, isValid and convert still need to be
written.
number 193 194 195

Alternatively you could have a readExpression


In Java which is done a character at a time:
if isValid //number operator number
Expression readExpression(){ readNum
convert line to expression
char[] line = new char[20]; if okay
Expression e;
This says divide the problem in two. First walk over readOp
line = readLine();
the array of characters checking that you have if okay
if (isValid(line))
characters that will convert to what you want, then {e = convert(line); then readNum
convert the entire array of characters. if not okay
return e}
Dealing with error filled input is difficult and this else{ println syntaxError
simplifies the task since you only do the conversion throw away rest of line
println(syntaxError);
on syntactically correct input.
return readExpression(); readExpression
You can only use this technique if your input data
can be looked at more than once without consuming
} where readNum and readOp still need to be
it. 196 } 197 written. 198
Summary Testing
Design is an iterative process so the designer may test that your program does what it was required to
need to return to an earlier stage for amendments and do go back to the specification
additions.
There are frequently several ways to solve a problem.
Lecture 10: Testing and Debugging test at the limits of data ranges
To find the best way solve the problem in the ways you
think are good and then compare the solutions for
Lecturer : Susan Eisenbach alter program if it fails with any legal input data
document what the program does in situations where
clarity. For extra material read part of Chapter 10 of the specification does not describe the intended
Errors identified and corrected at the design stage Java Software Solutions
are less expensive than those that survive to the
behaviour
implementation stage and beyond. This is the 10th lecture in which how to test the program should never be allowed to crash or
whether a program fulfils its specification and rubbish (an incorrect answer or inappropriate error
Some program somewhere has to convert characters
how to debug it, if it doesn't are covered.
typed in into numbers used in programs. message) be allowed to appear on the screen
Anything but the simplest input is difficult to do. draw up a test table
199 Susan Eisenbach 200 201

Not so straightforward test


The specification for Calculator Test data data
The program should accept two numbers, separated by Input Expected Comment Input Expected Comment
an arithmetic operator, and should produce the Outcome Outcome
correct arithmetic result, if this is calculable.
-3 ??? outside of specification
Numbers are non-negative whole numbers. 3+3 6 correct addition
6+ ??? outside of specification
Arithmetic operators are +, -, * and /. 10-2 8 correct subtraction
+ ??? outside of specification
Calculable means that the result must be finite, whole 3* 4 12 correct multiplication
= ??? outside of specification
and positive. 21 /3 7 correct exact division
a-b ??? outside of specification
22/3 7 correct whole num. division
Input consists of number operator number return. 0*0 0 at limits of specification
4- 11 cannot calculate appropriate error message
Input may be separated by spaces and is separated biggest number - 0 at limits of specification
22/0 cannot calculate appropriate error message
from the result by a new line. biggest number
0/0 cannot calculate appropriate error message
If the user fails to type in correct data then an error biggest number *1 biggest number at limits of number range
2&3 not an expression appropriate error message
message "not an expression" will be output. biggest number +1 overflow error outside of specification
3^4 not an expression appropriate error message
A potentially incalculable result will produce the error
202 203 204
message: "cannot calculate". biggest number *10 overflow error outside of specification
Test as you code Example test harness to test evaluate Alternatively, use incremental testing
Write the declarations and main program first.
class Expression{

bugs (technical term) are errors in programs int first;


char op;
All declarations for methods have to be
bugs are difficult to find in complete programs }
int sec;
written as well. These should include
test each method as soon as you have written void main(){
comments.
it Expression e;
e.first = readInt(); e.op = readChar(); e.sec = readInt(); The bodies of each method should be trivial.
two ways of testing methods: println(evaluate(e));
These are called stubs.
}
test harnesses - write a small program to test Execute the program. If there is a bug then
each method int evaluate( Expression e ) {
switch ( e.op ) { fix it.
incremental testing - use the whole program to case '+' : {return e.first + e.sec; }
Then replace one stub at a time. Each time
test each new method case '-' : {return e.first
case '*' : {return e.first
-
*
e.sec;
e.sec;
}
} testing the code.
either way, testing as you go takes up less time case '/' : {return e.first / e.sec; }
Bugs can always be isolated to the latest
then post testing
}
205 return 0; 206 added code. 207
}

Example stubs for testing the main program Calling the stubs Debugging complete code
Expression readExpression(){ class Expression {
Expression e; int first = 0; when a program goes wrong you need:
char op;
e.first = 2; int sec = 0; – what code was being executed
e.op = '*'; } – what data was being used
e.sec = 21;
void main(){ code being insert debugging code
return e;
}
String notCalculable = "cannot calculate"; tested need to produce a trace
Expression expr; main program entered
boolean isCalculable( Expression e ) { expr = readExpression();
return true; if ( isCalculable(expr) ) {println("= " + evaluate( expr ) );}
isCalculable entered
} else {println( notCalculable );} evaluate entered
}
Expression readExpression(){stub code goes here} <crash>
int evaluate( Expression e ) { boolean isCalculable( Expression e ) {stub code goes here}
assert (isCalculable(e)); int evaluate( Expression e ) {stub code goes here}
return 42; 208 209 210
}
Permanent tracing code Debugging data Summary
use a boolean constant at the top of the code Need to print out values of possible offending Test throughout program development to ease finding
bugs.
boolean tracing = true; variables
Use test harnesses and stubs to find bugs in methods.
at the start of each method foo include: Use another boolean constant for this: Test a program against its requirements.
if (tracing) {println( "foo entered" );}
boolean debug = true ; Test with typical data, then at limits then outside the
at the end of each void method include: specification.
Insert code where it might be needed:
if (tracing) {println( "foo exited" );} If a program does not work properly it needs to be
¿ Why don't non-void methods get this code as well? if debug {println("ch = " + ch);} debugged. Insert debugging code to find the source of
Write methods to print out classes: the error. Do this systematically.
When you don't want to see the trace you change the
value of tracing to false. Trace your program by hand. Time spent this way will
void printExpression(Expression e) be less than the time spent sitting at the machine
looking for bugs.
211 212 213

Another Calculator Start Off Calculation:


We will consider a program which can deal with a "long" read first operand
expression defined as follows: read operator
Lecture 11 : Abstract Data Types Expression=Operand,{Operator,Operand,} "="
Operand = int
calculate.
write out the result which is held in first operand.
Lecturer : Susan Eisenbach Operator =‘+’ | ‘-’| ‘*’ | ‘/’| ‘^’
The expression now corresponds to any arithmetic calculate:
For extra material read Chapter 12 of expression with several operators but without if operator isn't "="
brackets. read second operand
Java Software Solutions In the simplest case do 'left-to-right’ evaluation. Thus evaluate the expression
This is the 11th lecture on Java in which 3+4-5+6=(3+4)-5+6 assign the result to first operand
we define abstract data types and =(7-5)+6
=2+6
read operator
describe an actual use. =8 calculate.
The ideas embodied in the first Calculator could be What is wrong with this?
Susan Eisenbach 214 adapted to give pseudo-code along the following lines.215 216
Precedence Operations Required Stack Operations
Left-to-right evaluation only applies to operations of the 1. Insert a subexpression isEmpty returns true iff the stack has no
same precedence. Consider the expression elements in it.
2. Remove the most recently inserted
a+b*c^d/e=
subexpression empty returns an empty stack
Precedence rules
^ highest
3. Examine the most recently inserted operator. stack = empty | push( item, stack)
*/ high Better to have two data structures one for top returns the top element of the stack.
+- low numbers one for operators. push takes a stack and an item and returns
= lowest This data structure is called a stack. the stack with item added at the top.
The program will need to scan the input expression and Have you seen another data structure pop takes a stack and returns it with the top
can safely evaluate subexpressions from left to right element removed.
until a higher-precedence operator is encountered.
that looks like a stack?
The current evaluation will have to be suspended until
the higher-precedence operation has yielded a result.217 218 219

User defined types User defined types are not enough Many Haskell functions are polymorphic
Java cannot provide every data structure that fst :: ( a, b ) -> a Pair index
is needed by every programmer. Although user defined types are useful
Java lets you create new data structures using something like Haskell’s polymorphism is fst(3,”Hello”) of 3
important so that the user defined types do
its classes. not have to contain the type of the elements. Note that the type of fst involves two
When accessing elements of these user The latest Java now has generic types which type variables
defined data structures methods are used. are similar to polymorphic types.
since pair elements can be of any type
So instead of getting elements with x[i], like So now in Java it is possible to define lists,
arrays or x.i like fields in classes, the trees, etc which can be used for holding values
programmer has to write methods to get items of any type such as ints, chars or whatever is
from the user defined data structures. required by the program.

220 221 222


Java Generics Program using a Pair<T> Program using a Pair<S,T>
To declare a pair of two elements of the same void main() { void main() {

type in Java:
Pair<String> twoStrings; Pair<String,String> twoStrings;
twoStrings.a = "hello"; twoStrings.a = "hello";
class Pair<T>{ twoStrings.b = "world"; twoStrings.b = "world";
T a;
type variable declaration println(twoStrings.a);
T b; Pair<int,char> intChar;
Pair<int> twoInts; intChar.a = 3;
}
twoInts.a = 3; intChar.b = 'x';
To declare a pair of two elements of (possibly) twoInts.b = 4; println(intChar.b);
different types in Java: }
println(twoInts.a); }

class Pair<S,T>{ class Pair<S,T>{


S a; class Pair<T>{ S a;
T b; T a; T b;
} T b; }
}
type variable declarations

223 224 225

Access methods for a stack of


Generic methods items Using a stack
<<T> boolean isEmpty(Stack<T> s) {//code goes here
Methods can have generic types. } In your program you would need the following
declarations:
The generic types must come before the <T> Stack empty() {//code goes here

return type. //post: isEmpty(empty()) enum Operator{


} PLUS, MINUS, TIMES, DIVIDE;
Both the arguments and return type may <T> T top (Stack<T> s) {//code goes here }
be generic assert (! isEmpty(s)) :"no top of an empty stack"; Stack<int> numS;
<S,T> S first(Pair<S,T> p){ } Stack<Operator> opS;

return p.a; <T> Stack push (Stack<T> s, T item) {//code goes here Write push(numS,3) to push 3 onto numS
} and top(opS) is the top operator on the
} //post top(result)=item operator stack.
returns something of the first generic type
<T> Stack pop(Stack<T> s) {//code goes here
226 assert (isEmpty(stack)) :"cannot pop an empty stack"; 227 228

}
Using a stack calculate: Example: calculate 1+3*4 /2 =
if there is another item (operand or operator)
We have not said how the actual stack is implemented if it is an operand if there is another item (operand or operator)

as we have not shown the data declarations. Perhaps push it onto the numberStack, skip over the item,
if it is an operand

our stacks will be implemented as arrays – but they calculate the rest of the expression
push it onto the numberStack, Skip over the item,

don’t have to be. else if the operatorStack isEmpty or its top is of


calculate the rest of the expression
else if the operatorStack isEmpty or its top is of
When using a stack you don't use the actual data lower precedence than the item's precedence lower precedence than the item's precedence
declarations, because they don't model the data push the item onto the operatorStack, push the item onto the operatorStack,
structure (stack here) and may be changed. skip over the item 4
2 skip over the item

You only use the access methods that need to be calculate the rest of the expression calculate the rest of the expression

written: isEmpty, empty, pop, push and top. else pop the top two operands and the top operator, 12
3
6 /* else pop the top two operands and the top op,
evaluate the expression formed,
Use is independent of the implementation of the evaluate the expression formed,
push the result onto the numberStack,
71 + push the result onto the numberStack,
method. calculate the rest of the expression
calculate the rest of the expression

229 230 231

An array implementation of a An array implementation of a


stack stack Modelling data relationships
Declaration of this stack: Data declarations of this stack: Arrays and records don't model everything.
class Stacks{ In Java you can define your own structures.
int items = new int[20]; Whether or not Java data structures are
5 suitable follow a three stages process for
int pointer = 0;
establishing any data-store:
//methods go here – Discern the need for a data store and establish its
} characteristics and the interrelationships of its components.
– Make arrangements to create a data store within the program
‘*’
pointer = ___ when the stack is empty which faithfully reflects the real-world structure.
‘+’ ‘-’ ‘/’
– Produce code to manage the structure - i.e. to examine the
pointer = ___ when the stack is full data store and to insert and remove items.
1 2 3 4 5 6
232 233 234
Important jargon Summary
In general these operations will not be as simple as for When designing a data structure a programmer must:
arrays and each operation will be realised as a – establish those characteristics dictated by the problem
separate method, called an access method. – create a data structure that has these characteristics
In Java you can consider the use and creation of the – produce code to manage the structure.
data structure entirely separately. Operations designed to manage a data structure are called access
methods. A collection of such operations, all applicable to a
The programmer can consider how the data store will particular type of data structure, is called an abstract data type.
be accessed without needing to bother about the A stack is an example of an abstract data type.
practical details of controlling and manipulating Arithmetic expressions can be evaluated, by using stacks to store
storage - i.e. in the abstract. For this reason, the both numbers and operators until needed.The use of the stacks
collection of operations is often known as an abstract ensures that the correct order of operations is observed.
data type. Next term you will look at many different abstract data types
since they are a very powerful programming tool.
Using abstract data types is a major tool for program
decomposition in modern programming practice.
235 236

You might also like