Generic Class • One that is parameterized by type » Works when feature semantics is common to a set of types • On object declaration the parameter is assigned a type Genericity » For example Parameterizing by Type catalogue : ARRAY [ PERSON ] » We want an array of references to persons » All the array operations for catalogue are customized to use persons 1 Common Generic Classes 2 Your Generic Classes • Collection classes – classes that are collections of objects • You can write generic classes • Why is this useful? » Strong typing requires specifying a type » But feature semantics is independent of type » reuse » reliability • Examples » Sets, Stacks, Arrays, Queues, Sequences a : ARRAY [ MATRIX_ELEMENT ] a : ARRAY [ INTEGER ] a : ARRAY [ STACK [ ELEPHANTS ] ] 3 4 Understanding Genericity Generic Stack • We need » class STACK [ G ] feature count : INTEGER -- number of elements lists of INTEGER, lists of BOOK, lists of STRING etc. • Without genericity we have » empty : BOOLEAN is do ... end INTEGER_LIST, BOOK_LIST, STRING_LIST full : BOOLEAN is do ... end • Problem — Reusability. » The basic operations (e.g. add, remove) are essentially the same. » Have to re-write essentially the same code over and over again. » Violation of the Single Choice Principle — changing LIST requires multiple changes, instead of a change at a single point. item : G is do ... end put ( x : G ) is do ... end remove is do ... end end -- STACK • Can use parameter G wherever a type is expected 5 Generic Array 6 Using the Generic Array circus : ARRAY [ STACK [ ELEPHANTS ] ] create circus.make ( 1 , 200 ) class ARRAY [ P ] creation make feature make ( minIndex , maxIndex : INTEGER ) is do ... end lower, upper, count : INTEGER st_el : STACK [ ELEPHANTS ] -- element to put in the array create st_el put ( value : P ; index : INTEGER ) is do ... end circus.put ( st_el , 30 ) -- put an element into the array item alias “[]”, infix “@” (i:INTEGER): P is do ... end st_el2 : STACK [ ELEPHANTS ] end -- ARRAY st_el2 := circus @ 101 st_el2 := circus[101] 7 -- get an element from the array -- alternative notation 8 Types of Genericity Constrained Genericity • Types • Used when the generic type parameters must satisfy some conditions » Unconstrained » Constrained • The following makes sense only if P has the feature ≥ • The previous examples showed unconstrained genericity class VECTOR [ P ] feature ... minimum ( x , y : P ) : P is do if x ≥ y then Result := y How we enforce else constraints is Result := x discussed in end Inheritance Techniques ... end » Any type could be passed as a parameter 9 Discussion on Genericity 10 Non-generic Java Stack public class Stack { private int count; private int capacity; private int capacityIncrement; private Object[] itemArray; // instead of ARRAY[G] • What programming languages offer genericity that you know of? Java? C++? Other? • C++ has the template: Set < int > s ; • Java 5 has added genericity Stack() { //constructor limited to class name count= 0; capacity= 10; capacityIncrement= 5; itemArray= new Object[capacity]; } • What is the effect of genericity on » compile time » size of the generated code » execution time » execution space public boolean empty() { return (count == 0); } • Warning: generics cheap in Eiffel – expensive in C++ 11 12 Java Stack (cont.) Java Stack (cont.) public void push(Object x) { if(count == capacity) { capacity += capacityIncrement; public Object peek() { if(count == 0) Object[] tempArray= new Object[capacity]; for(int i=0; i < count; i++) tempArray[i]= itemArray[i]; return null; else return itemArray[count-1]; } itemArray= tempArray; } itemArray[count++]= x; } } public Object pop() { public class Point { if(count == 0) return null; else return itemArray[--count]; public int x; public int y; } } 13 Java Stack runtime error 14 Does run-time vs. compile time matter? class testStack { • Principle: When flying a plane, run-time is too late to find out that you don’t have landing gear! public static void main(String[] args) { Stack s = new Stack(); Point up p erRight = new Point(); up p erRight.x= 1280; // b reaks information hiding up p erRight.y= 1024; // cannot guarantee any contract • Always better to catch errors at compile time! • This is the main purpose of Strong Typing [OOSC2, Chapter 17]. s.p ush("red"); s.p ush("green"); // p ush some String s.p ush("b lue"); // ob jects on the stack s.p ush(up p erRight); // p ush a POINT ob ject on the stack while(!s.emp ty()) { • Genericity helps to enforce Strong Typing, i.e. no runtime typing errors » LIST[INTEGER] » LIST[BOOK] » LIST[STRING] // cast all items from OBJEC T String color = (String) s.p op (); // to STRING in order to p rint System.out.p rintln(color); }}} // causes a run-time error // C lassC astExcep tion: Point at testStack.main(testStack.java:18) // W ith genericity, it is a compile time error 15 16