Subtyping --------- Chapter 15 (Pierce) - Universal Polymorphism \forall A.A->A - Existential Polymorphism \exists q. q * q * int -> q -> int * q -Subtyping Java Key Idea -------- Type t1 is a subtype of t2 if all values with type t1 can be used in operations where values of type t2 are expected. Notation t1 <= t2 ------ (reflexivity) t <= t t1<=t2 t2<= t3 --------------- (transitivity) t1 <= t3 Extending the type system G |- e: t1 t1 <= t2 -------------------- (subsumption) G |- e: t2 t ::= ... | Top (like the Object in Java) -------- t <= Top Example program: let f = \x:Top.x in (f 2, f true) Typing derivation for example program: Derivation D = ------------------------ ------------ f:top->top |- true : bool bool <= top ------------------------ --------------------------------------- f:top->top |- f:top->top f:top->top |- true : top --------------------------------------------------- f:top->top |- f true : top Complete derivation = --------------------- f:top->top |- 2 : int int <= top ------------------------ --------------------------------- f:top->top |- f:top->top f:top->top |- 2 : top --------------------------------------------------- f:top->top |- f 2 : top D ------------------------ ------------------------------------------------- |- \x:top.x : top -> top f:top->top |- (f 2, f true) : top* top ------------------------------------------------------ . |- let f = \x:top.x in (f 2, f true) : top * top If we used universal polymorphism we would get a more precise type: let f = /\ A. \x: A. x in (f[int] 3, f[bool] true) : int * bool If we extend the types to include n-tuples: t::= ... | t1 * t2 * .. * tn e::= ... | (e1, e2, ..., en) | e.i Typing rules: G |- e1: t1 ... en : tn ------------------------------------------- G |- (e1, e2, ..., en) : t1 * t2 *... * tn G|- e: t1* ... * tn 1 <= i <= n -------------------------------- G |- e.i : ti Good subtyping rule: m <= n ----------------------------- (width subtyping) t1 * ... * tn <= t1 *... * tm This rule: n <= m ----------------------------- t1 * ... * tn <= t1 *... * tm is bad, because there exists a program that type checks but the evaluation gets stuck. Example of the program: let L = (1, 2, 3) in L.4 (Covariant rule) t1 <= t1' ... tn <= tn' -------------------------------- (depth subtyping) t1 * ... * tn <= t1' * ... * tn' e.g. int * bool <= top * top (Contravariant rule: bad for tuples!!) t1' <= t1 ... tn' <= tn -------------------------------- (depth subtyping) t1 * ... * tn <= t1' * ... * tn' Extending the types with n-ary sum: t ::= ... | t1 + .. + tn e ::= ... | in_i [t] e | case e of (in_1 x => e1 | ... | in_n x => en) G |- e: ti 1 <= i <= n ------------------------------------------ G |- in_i [t1 + .. + tn] e : t1 + ... + tn G|- e: t1 + .. + tn \forall i: G, x: ti |- ei : t ------------------------------------------------------ G |- case e of (in_1 x => e1 | ... | in_n x => en) : t