contents
play

Contents What is genericity? Alternatives: Genericity and its - PDF document

Contents What is genericity? Alternatives: Genericity and its Implementation multiple instantiation casting Checking correctness of generic types at Meyer Chapter 10, 16.4 definition: constrained genericity Subtyping


  1. Contents • What is genericity? • Alternatives: Genericity and its Implementation – multiple instantiation – casting • Checking correctness of generic types at Meyer Chapter 10, 16.4 definition: constrained genericity • Subtyping relations between instances • Implementation of genericity • Anchor Types 1 2 What is Genericity? Examples of Genericity • We don’t want to write a Stack for Integers, floats, • We have seen Stack[G]. employees, etc. • Vectors of numbers with addition and – More effort – Versions will become inconsistent, extra debugging effort ordering • Write once, use for many types • A map of (key, element) pairs • Implementations: – C++: templates • A binary search tree for types that have a ≤ – Eiffel: constrained genericity function – Java: not present, expected in Java 1.5 • Problem: different types allow for different operations. 3 4 Two Ideas The Alternative: Casting • Automatic multiple instantiation (C++) • How do we write a stack in Java? – No genericity (expected in 1.5, in 2004) • Automatic casting – Stack is a stack of Objects – Every push and pop uses a cast 5 6

  2. Reminder: cast up Reminder: cast down • cast: compile-time construct to change • Cast down (narrowing): see an object as a subtype changes the static type (compile-time type) – No guarantee that it works of an object – Rectangle r = (Rectangle) f; //Java – Rectangle *r = dynamic_cast<Rectangle *> f; //C++ • Cast up (widening): See an object as if it – Check for legality at runtime: if incorrect, were of supertype. Always legal . • throw exception (Java) or • assign NULL (Eiffel, C++) – Figure f = (Figure) new Rectangle(); – Useful for such things as: “Print diameter of all or rectangles in list of figures” – Figure f = new Rectangle(); 7 8 Casting and Introspection Casting Instead of Genericity • Can check beforehand if a cast is legal Stack s; Circle c; Figure f; Rectangle r; s.push((Object) c); – In Java: s.push((Object) c); if(f instanceof Rectangle) f = (Figure) s.pop(); //legal narrowing r = (Rectangle) f; r = (Rectangle) s.pop(); //illegal narrowing else r = null; • Alternative to Genericity – In C++ (similar in Eiffel) if(Rectangle *r = dynamic_cast<Rectangle *> f) • Effectively disables static type checking in Java! OK • Errors caught during run time, not compile time. else f is not a rectangle 9 10 Checking Correctness: Vector Checking Correctness class Vector[G]{ G get(int i){...} put(int i, G item) {...} • Not all templates can be used with all types! infix “+”(other: Vector[G]): Vector[G]{ Vector[G] result; G item; require length = other.length; for (i = 0; i < length; length++){ item = item(i) + other.item(i); result.put(i, item); } return result; } } 11 12

  3. Checking Correctness Correctness at Instantiation • How do we make sure a template is correct? • Instantiation: creation of code from a declaration Stack<Integer> or similar • Parameter may allow only certain • First method to check template correctness. Used in C++ operations: we can add numbers, not • When template is encountered – Check syntax employees – No type checks • Vector[Employee] is nonsense. • When template is used, check for correctness: – instantiate template by creating code as if it were a macro – check instantiated code • Drawback? • How do we make sure? 13 14 Correctness at Instantiation Correctness at Definition • Drawback: • Second method to check template correctness: The Eiffel Method – Have to tell user the constraints for the • Give argument a type, allow only instantiations of parameter correct type: Constrained Genericity – You never know if a template is “correct” • Classname[G -> H] instantiates generic type unless you have used it in all possible ways Classname, in which G must be subclass of H • Fits “strong typing” idea 15 16 Correctness at Definition Correctness at Definition class Vector[G -> Numeric ]{ G get(int i){...} put(int i, G item) {...} deferred class Numeric feature infix “+”, infix “-”, infix “*”, prefix Vector[G] plus(other: Vector[G]){ “-”, zero(), one() Vector[G] result; end G item; require length = other.length; • A ring: two groups, defined by (*,1) and for(i = 0; i < length; length++){ (+,0), the latter of which is commutative, item = item(i) + other.item(i); result.put(i, item); such that * distributes over +. } return result; 17 18 }

  4. Correctness at Definition Correctness • class Sortable[G->Comparable]... In favor of correctness at In favor of correctness at instantiation definition • class Dictionary[G->Hashable, H] Flexibility: No need to Correctness clear when • class Stack[G] (= Stack[G -> Object] ) create classes that template written (good – Any type has ==, !=, clone, equal,... combine all needed for libraries) functionality and to derive from them Both have Correctness at compile time! 19 20 Subtyping Subtyping • If Truck is derived from Vehicle, is • If Truck is derived from Vehicle, is Stack[Car] derived from Stack[Vehicle]? Stack[Car] derived from Stack[Vehicle]? • No. (Sorry.) We could otherwise perform (code in Java): Stack[Car] cs = new Stack[Car](); Stack[Vehicle] vs = cs; Invalid code! vs.push(Truck t); Car c = cs.pop(); // would assign t to car • Sharing does not work, copying is OK: • We can write conversion operators that take Stack[Car] and yield a new object Stack[Vehicle]. 21 22 Implementation Multiple Instantiation • First implementation: C++ Method • The compiler perspective • Like macro expansion • Translating Java + templates to Java. How • For every type X if Stack[X] occurs in code, would you do it? recompile code for Stack[G] with X in place – Odersky and Wadler, Pizza into Java, translating theory into practice, Proc. Symposium on Principles of Programming Languages (POPL’97), of G 146– 159, 1997. – This is when error checks are done • Two alternatives • In place of means simple syntactic – Multiple Instantiation substitution – Casting 23 24

  5. Casting: Translation Into Java Casting up and down Class Stack[G]{ push(G f){ ... } • Second implementation } • Classname[G -> H] is implemented by Stack[Figure] s; Classname , in which G is replaced by H (If no H Circle c; present, use Object .) Figure f; Rectangle r; • Every transfer from and to Classname is cast Object o; s.push(c); • At compile time, we can check that s.push(r); – Generic type definition is OK when instantiated with H s.push(o); – Class instantiations are correct (use subclass T of H ) f = s.pop(); o = s.pop(); c = s.pop(); 25 26 Casting: Translation Into Java Multiple Instantiation vs. Casting //compile code with Figure in place of G Class Stack{ Class Stack[G->Figure]{ Multiple instantiation: Casting push(Figure f){ ... } push(G f){ ... } } } • Takes more space for •Takes less space Stack s; // OK: Polygon Stack[Polygon] s; program text derived from Figure Triangle t; • No Time overhead Triangle t; •No Time overhead Polygon f; Polygon f; Rectangle r; Rectangle r; Note: Casting Object o; Object o; unnecessary: we can s.push((Figure) t); s.push(t); s.push((Figure) r); s.push(r); check correctness at // compile-time error! s.push(o); compile time! f = (Figure) s.pop(); f = s.pop(); o = (Object) s.pop(); o = s.pop(); //compile-time error t = s.pop(); 27 28 Final Problem: Anchor Types Anchor Types class Vector[G -> Numeric]{ deferred class Numeric • How do we complete the definition of G get(int i){...} feature put(int i, G item) {...} Numeric, so that it can be used for Vector? infix “+”, infix “-”, infix “*”, prefix “-”, zero(), Vector[G] plus(other: one() Vector[G]){ end Vector[G] result; G item; • A class C is numeric if it has a plus operator require length = other.length; that takes two arguments of type C and for(i = 0; i < length; length++){ returns a result of type C item = item(i) + other.item(i); result.put(i, item); } return result; } 29 30

  6. Anchor Types Anchor Types deferred class Numeric class Vector[G -> Numeric]{ deferred class Numeric feature G get(int i){...} feature infix “+”(other: like Current): like Current infix “+”, infix “-”, put(int i, G item) {...} ... infix “*”, prefix “-”, end zero(), one() Vector[G] plus(other: end Vector[G]){ end Vector[G] result; G item; • Like current means “of same type as current instance”, e.g. First proposal: write require length = other.length; class Integer inherit Numeric feature infix “+”(other: for(i = 0; i < length; length++){ Numeric): Numeric{…} ... item = item(i) + end other.item(i); Won’t work vector[Real] cannot result.put(i, item); has method infix “+” with type Integer X Integer → contain arbitrary Numeric s ! } return result; Integer. } 31 32 Conclusions • Genericity useful if static typing is important (i.e., always) • Implement by multiple instantiation or casting • Check correctness at instantiation or at definition (constrained genericity) • Anchor types help define interfaces 33

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend