GenericsType parametersGenerics in AdaInstantiating an Ada genericImplementationC++ templatesJava generics: exampleExample continuedSlide 9Generic typesSubtypes of generic typesWildcardsRestricted type parameters and wildcardsEmbedded Type ParametrizationImplementation: Type erasureBug, not a featureMoralsGenericsType parametersThe definition of “ArrayApplier” in applier.java and applier2.java allows any function from int to int. But suppose you want to write a single array applier for any function from type T1 to T2?Dynamic method binding allows the type of “self” to be variable, but there’s no way to get 2 variable types.Generics in AdaEssentially a structured macro.generic type Item is private; type ItemArray is array (Integer range <>) of Item; with function f(X: Item) return Item; procedure ArrayApplier(A,B: in out ItemArray) begin for I in 1 .. A’Last loop B[I] = f(A[I]); end loop endInstantiating an Ada genericfunction incr(I: Integer) return Integer is begin return I+1; end;type IntArray is array(Integer range<>) of Integer;function ApplyIncr is new ArrayApplier(Integer,IntArray,incr);ImplementationEach instantiation of the generic is built by a preprocessor at compile time, and compiles to a separate routine.Like a macro.C++ templatestemplate <typename T>int compare(const T &v1, const T &v2){ if (v1 < v2) return -1; if (v2 < v1) return 1; return 0;}int I,J; compare(I,J); // int comparedouble X,Y; compare(X,Y); // double comparecompare(I,X); // compiler errorJava generics: exampleinterface UnaryFun<T,S> { public S f(T x); }class IntSqrt implements UnaryFun<Integer,Float> { public Float f(Integer i) { return new Float(Math.sqrt(i)); }}Example continuedclass Applier<T,S> {public void ApplyToArray( UnaryFun<T,S> Q, T[] A, S[] B) { for (int i=0; i < A.length; i++) B[i] = Q.f(A[i]); }}Example continued… main …Integer A[] = new Integer[] {1,2,3};Integer C[] = new Integer[3];IntSqrt ISQ = new IntSqrt();Applier<Integer,Float> IFApp = new Applier<Integer,Float>();IFApp.ApplyToArray(ISQ,A,C);Generic typesLinkedList list = new LinkedList)();list.add(new Integer(1));Integer num = (Integer) list.get(0);LinkedList<Integer> L = new LinkedList<Integer>();L.add(new Integer(1));Integer num = list.get(0);Subtypes of generic typesLinkedList<Integer> LI = new LinkedList<Integer>();LinkedList<Object> LO = LI; // Type error!LO.add(new String(“Hello”));Difference between extensional and abstraction view of types.Therefore if a method has a parameter of type LinkedList<Object> you can’t pass an argument of type LinkedList<Integer>Wildcardsvoid printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e);}LinkedList<Integer> L;printCollection(L);Restricted type parameters and wildcards<T extends shape>, <T super shape><? extends shape>, <? super shape>void drawAll(List<? extends shape> L) { for (shape S : L) draw(S); }Type definition for max(c) (simplified): public static <T extends Comparable<? super T>> T max(Collection<T> coll)Embedded Type ParametrizationLinkedList<LinkedList<Integer>>static List<List<? extends Shape>> history = new ArrayList<List<? extends Shape>>;public void drawAll(List<? extends Shape> shapes) {history.addLast(shapes);for (Shape s: shapes) s.draw(this); }Implementation: Type erasureNo record of the parameter value at run time.If L is of type LinkedList<Integer>, all the interpreter knows at runtime is that it is of type LinkedList.One subroutine for ApplyToArray, not a separate routine for each different argument type (as in Ada and C++).Possible because parameters are reference types and all the same size.Bug, not a featureDone for compatibility with legacy code.In complex cases, leads to need for casts, runtime type checking, type unsafe code.Morals•Backward compatibility is the source of much grief.•(Forward compatibility is a myth.)•No type theory of complex entities (collections, functions, etc.) is both adequate and
View Full Document