EECE 310 Software Engineering Iteration Abstraction Learning Objectives

EECE 310: Software Engineering Iteration Abstraction

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Understand the design issues for iterators • Design iterators that support concurrency

Problem • Consider the Int. Set ADT introduced earlier • Let’s say you want to compute the sum of elements in the set. How would you do it ? – Add a member function compute. Sum – Copy the rep to another array and return it – Add an indexing operation to the ADT – Add a new iterator abstraction • Which method would you choose and why ?

Iteration Abstraction • General way to iterate over the elements of an ADT without tying the iteration to a specific operation (e. g. , summation) – Efficient in space and time (as far as possible) For each element e of the ADT: Perform operation o on e

Implementation • Implemented using two entities: 1. Generator: Keeps track of the state of the iteration and exposes operations to actually perform the iteration 2. Iterator: Operation of an ADT that returns a generator object to begin the iteration process

Iteration Abstraction: Generators ADT state 1 Client Code 1 Generator objects state 2 Client Code 3

Generator: Example public interface Iterator<T> { public boolean has. Next() // EFFECTS: Returns true if there are more elements to // yield, else returns false public T next( ) throws No. Such. Element. Exception // MODIFIES: this // EFFECTS: If there are more results to yield, // returns the next result and records the state of this // Otherwise, throws No. Such. Element. Exception

Iterator: Int. Set Example public class Int. Set {. . . public Iterator<Integer> elements ( ) // EFFECTS: returns a generator that will produce // all the elements of this, each exactly once, // in arbitrary order. // REQUIRES: this must not be modified while // the generator is in use. }

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Design iterators that support concurrency

How do we use iterators ? ADT (e. g. , Int. Set) Has iterator methods that return generator objects, e. g. , elements Generator object: implements the Java iterator interface): 1. has. Next 2. next Step 1: Client invokes the iterator operation on ADT and stores the returned generator object Int. Set s = new Int. Set(v); …. Iterator g = s. elements(); Step 2: Perform the iteration using the has. Next and next methods of the generator object while ( g. has. Next() ) { Integer o = g. next( ); int i = o. int. Value(); } Optional Step: May pass the generator object to different procedures for doing the operation e. g. , int m = compute. Max(g);

Some points on using Generators • Using code interacts with a generator via the iterator interface (defined in java. util package) • Using code must obey the constraint imposed on it by the iterator’s requires clause (given after the EFFECTS clause) • Generators can be passed as arguments and returned as results by procedures • Generators may be primed before using them in loops • Generators may loop infinitely, e. g. , list of prime numbers

In-class Exercise • Write a procedure that iterates over the elements of the Int. Set ADT and prints all Integers that exceed a certain threshold, max

Solution: Method 1 public static void print. Exceeds(Int. Set s, int threshold) throws NPException { // EFFECTS: If s is null, throws Null. Pointer. Exception, // Otherwise, Print all elements in s that exceed the given threshold } Iterator<Integer> g = s. all. Elements(); try{ while ( true ) { int x = ( g. next() ). int. Value(); if (x > threshold) System. out. println(x); } } catch( No. Such. Element. Exception e) { } // Do nothing if we run out

Solution: Method 2 public static void print. Exceeds(Int. Set s, int threshold) throws NPException { // EFFECTS: If s is null, throws Null. Pointer. Exception, // Otherwise, Print all elements in s that exceed the threshold } Iterator<Integer> g = s. all. Elements(); while ( g. has. Next() ) { int x = ( g. next() ). int. Value(); if (x > threshold) System. out. println(x); } }

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Understand the design issues for iterators • Design iterators that support concurrency

Implementing Iterator methods public class Int. Set { private vector<Integer> els; // The rep . . . public Iterator<Integer> elements ( ) // EFFECTS: returns a generator object that will // produce all the elements of this, each exactly // once, in arbitrary oder. // REQUIRES (POST): this must not be modified while // the generator is in use. … }

Iterator Methods • Must be declared as public method of the ADT • One iterator method for every iterator • Can take in arguments, but not necessary • Must return the generator corresponding to the iteration

Implementing Iterator methods public class Int. Set { private vector<Integer> els; // The rep . . . public Iterator<Integer> elements ( ) // EFFECTS: returns a generator object that will // produce all the elements of this, each exactly // once, in arbitrary oder. // REQUIRES (POST): this must not be modified while // the generator is in use. return new Int. Set. Gen(this); } Generator object

Implementing Generators • Int. Set. Gen is declared as a nested class within the Int. Set ADT and it’s scope is private – Clients cannot create Int. Set. Gen objects except through the iterator method of the Int. Set ADT – Clients cannot directly access any operation of Int. Set. Gen except through the iterator interface – Int. Set. Gen has undeterred access to the private methods of the Int. Set including its rep (i. e. , els)

Int. Set. Gen: Declaration public class Int. Set { private vector<Integer> els; // The rep public Iterator<Integer> elements( ) { // Iterator // EFFECTS: … return new Int. Set. Gen( this ); } private static class Int. Set. Gen implements Iterator<Integer> { // Generator object returned by elements … }

Int. Set. Gen: Rep and Constructor private static class Int. Set. Gen implements Iterator<Integer> { private int index; private Int. Set s; Passed in by the elements() method of the Int. Set ADT } // Constructor Int. Set. Gen(Int. Set is) { // REQUIRES: is!= null // EFFECTS: Initializes the generator for a // new iteration cycle s = is; index = 0;

Int. Set. Gen: has. Next operation public boolean has. Next( ){ // EFFECTS: If not reached the end // the elements vector, return true // otherwise, return false if ( index == s. els. size( ) ) return false; Int. Set ADT’s Rep – can else access this because it is return true; declared as a } nested class

Int. Set. Gen: next operation public Integer next( ) throws No. Such. Element. Exception { // EFFECTS: If there is a next object, return it // Otherwise, throw the No. Such. Element. Exception if ( has. Next( ) ) return s. els. get(index++); else throw new No. Such. Element. Exception(“Int. Set. elements”); } Use the name of the iterator method that produced the generator object

Generators: Points to note • Constructor must “copy in” the ADT reference – Also, initialize any other fields of the generator object • has. Next() should never advance the iteration – Corollary: It must be legal to call has. Next as many times as one can, and the result must be the same • next() must return the current object AND must advance the state of the iteration (if possible) – But should NOT require that has. Next() is called before

In-class exercise • Implement an Iterator for the Int. Set ADT, to return all integers of the Int. Set that are greater than a certain threshold, threshold. You’d use the iterator as follows (for example): Iterator<Integer> isi = is. greater. Than(threshold); while ( isi. has. Next() ) { Integer i = isi. next(). int. Value(); System. out. println(i + “ “);

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Understand the design issues for iterators • Design iterators that support concurrency

Design Issues: Multiple Iterators • Types may sometimes have multiple iterators • Examples: – Forward. Iterators, Reverse. Iterators for ordered collections such as lists – Iterators that return elements satisfying a certain critereon (say, within a specified range) – Iterators that perform some operation on their elements prior to returning them (e. g. , sorting)

Design Issues: Changes during Iteration • Default behavior so far: Disallow changes during iteration (specified in post-REQUIRES clause) • If changes are allowed, what are its semantics ? – State of iteration is what it was when the generator was created (requires creating copy) – Iteration sequence changes when changes occur to ADT (difficult to ensure consistency of state) • How do we reset iterator to go back in the collection ? • What if the current element is removed in a list ?

Design Issues: Can the generator itself change the ADT ? • The generator can change the rep of the ADT as long as it does not change the abstraction – Example: An iterator that returns the elements of an un-ordered collection such as set in sorted order may sort the collection during the process of iteration • Iterator changes the abstraction exposed by ADT – This is usually best avoided unless there is a compelling need. For example, iterating over a task list may itself spawn new tasks to be added to the list.

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Understand the design issues for iterators • Design iterators that support concurrency

Concurrent Iterators: Read only • Assume that we want to iterate over a list in two separate threads, but without modifying the list. Is this allowed ? – Yes, as long as we keep the generator objects separate. i. e. , we do not share generators – Each generator keeps track of where it is in the iteration – no changes to the state of the ADT – We need to make the iterator method synchronized (why ? )

Concurrent Iterators: Read-Write Thread 1 Thread 2 Iterator<Integer> g = is. elements(); is. add(1); is. add(2); is. add(3); is. add(4); is. remove(2); while ( g. has. Next() ) { Integer i = g. next(); System. out. println(i + “ “); } No guarantees about what iterator returns

How to solve the concurrent iterator problem ? • Disallow concurrent writes by taking a lock – Also disallows concurrent reads – performance ! – Need to explicitly release lock when done • Make a copy of the collection before iteration – Expensive ! • Throw a concurrent modification exception

Concurrent modification exception • Exception thrown when the ADT is modified concurrently (or not), during the iteration – Thrown to the thread that performs the iteration – Up to the thread what it wants to do with it – Only one exception per concurrent modification will be thrown • Concurrent. Modification is checked exception – So need to check for it/propagate in client

Learning Objectives • Define the basic elements used in iterators • Use iterators to iterate over a collection • Implement iterators and the associated generator classes for an ADT • Design iterators that support concurrency
- Slides: 35