Chapter 15 Benjamin Pierce Types and Programming Languages Varieties of Polymorphism
• Parametric polymorphism A single piece of code is typed generically – Imperative or first-class polymorphism – ML-style or let-polymorphism • Ad-hoc polymorphism The same expression exhibit different behaviors when viewed in different types – Overloading – Multi-method dispatch – Intentional polymorphism • Subtype polymorphism A single term may have many types using the rule of subsumption allowing to selectively forget information Simple Typed Lambda Calculus
t ::= terms x variable x: T. t abstraction t t application
T::= types T T types of functions Type Rules
t : T t ::= terms x : T x variable (T-VAR) x : T x: T. t abstraction , x : T t : T 1 2 2 (T-ABS) x : T1. t2 : T1 T2
T::= types t : T T t : T 1 11 12 2 11 (T-APP) T T types of functions t1 t2 : T12
::= context empty context , x : T term variable binding Records New syntactic forms New Evaluation Rules extends t ::= …. Terms: i 1..n i 1..n {li=ti } record {li=vi }. lj vj(E-ProjRCD) t.l projection
t t’ v ::= …. Values: i 1..n (E-Proj} {li=vi } records t.l t’.l T ::= …. types: {l :T i 1..n } record type i i tj t’j (E-Tuple) i 1..j-1 i j..n i 1..j-1 k j+1..n New typing rules {li=vi , li=ti } {li=vi ,lj=t’j,lk=tk } For each i t : T i i (T-Tuple) i 1..n i 1..n {li=ti } : { li: Ti }
t: { l : T i 1..n } i i (T-Proj)
t.lj : Tj Record Example
(r : {x: Nat}. r.x) {x=0, y=0 }
{x: Nat, y: Nat} <: {x: Nat}
t : S S <:T (T-SUB) t : T
t : T T t : T 1 11 12 2 11 (T-APP) t1 t2 : T12 Healthiness of Subtypes
S <: S (S-REFL)
S <: U U <:T (S-TRANS) S <:T Width Record Subtyping
i 1..n+k i 1..n {li:Ti } <: {li:Ti } (S-RCDWIDTH)
{x: Nat} has at least the field x of type Nat
{x: Nat, y : Nat} has at least the field x of type Nat and the field y of type Nat
{x: Nat, y: Bool} has at least the field x of type Nat and the field y of type Bool
{x: Nat, y: Nat} <: {x: Nat}
{x: Nat, y: Bool} <: {x: Nat} Record Depth Subtyping
For each i S <: T i i (S-RCDEPTH) i 1..n i 1..n {li:Si } <: {li:Ti } {x: {a: Nat, b: Nat}, y: {m:Nat}} <: {x: {a: Nat}, y: {}}
{a:Nat, b: Nat} <: {a: Nat} (S-RCDWIDTH) {m: Nat} <: {} (S-RCDWIDTH)
(S-RCDEPTH) {x: {a: Nat, b: Nat}, y: {m: Nat}} <: {x: {a: Nat}, y: {}} {x: {a: Nat, b: Nat}, y: Nat} <: {x: {a: Nat}, y: Nat}}
{a:Nat, b: Nat} <: {a: Nat} (S-RCDWIDTH) Nat <: Nat (S-REFL)
(S-RCDEPTH) {x: {a: Nat, b: Nat}, y: Nat} <: {x: {a: Nat}, y: {}} {x: {a: Nat, b: Nat}, y: {m: Nat}} <: {x: {a: Nat}}
{x: {a:Nat, b: Nat}}, {y: {m: Nat}} <: {x: {a: Nat}, b:Nat}} (S-RCDWIDTH)
{a: Nat, b: Nat} <: {a: Nat} (S-RCDWIDTH)
(S-RCDEPTH) {x: {a: Nat, b: Nat} <: {x: {a: Nat}}
(S-TRANS) {x: {a: Nat, b: Nat}, y: {m: Nat}} <: {x: {a: Nat}} Field Permutation
{k :S j 1..n } is a permutation of {l :T i 1..n } j j i i (S-RCDPERM) j 1..n i 1..n {kj:Sj } <: {li:Ti } Record Subtying
• Forgetting fields (S-RCDWIDTH) • Forgetting subrecords (S-RCDEPTH) • Reordering fields (S-RCDPERM) Naïve Handling of Functions S <: T S <: T 1 1 2 2 (S-ARROWN) S1 S2 <: T1 T2 n:{x: Nat, y: Nat} n.x +1 : Nat n:{x: Nat, y: Nat} n.y +2 : Nat} (T -RCD) n:{x: Nat, y: Nat} {x: n.x +1 , y: n.y +2}) : {x: Nat, y: Nat} (T-ABS) n:{x: Nat, y: Nat}. {x: n.x +1 , y: n.y +2}) : {x: Nat, y: Nat} {x: Nat, y: Nat}
{x:Nat, y: Nat} <: {x: Nat} (S-RCDWIDTH) {x:Nat, y: Nat} <: {x: Nat, y: Nat} (S-REFL) (S-ARROWN) {x:Nat, y: Nat} {x:Nat, y: Nat} <: {x: Nat} {x: Nat, y: Nat} (T-SUB) n:{x: Nat, y: Nat}. {x: n.x +1 , y: n.y +2}) : {x: Nat} {x: Nat, y: Nat} 1 : Nat (T-RECD) {x: 1} : {x: Nat} (T-APP) n:{x: Nat, y: Nat}. {x: n.x +1 , y: n.y +2}) {x:1} : {x: Nat, y: Nat} Handling of Functions T <: S S <: T 1 1 2 2 (S-ARROW) S1 S2 <: T1 T2
•Arguments types are handled in reversed way (contravariant) •Result types are handled in the same direction (covariant) Top type
T <: Top (S-TOP) Properties of the subtyping relation
• Preorder on types SOS for Simple Typed Lambda Calculus
t ::= terms t1 t2 x variable t1 t’1 x: T. t abstraction (E-APP1) t1 t2 t’1 t2 t t application t t’ v::= values 2 2 (E-APP2) v t v t’ x: T. t abstraction values 1 2 1 2
( x: T11. t12) v2 [x v2] t12 (E-APPABS) T::= types Top maximum type T T types of functions Type Rules t : T x : T S <: S (S-REFL) (T-VAR) x : T
, x : T1 t2 : T2 (T-ABS) S <: U U <:T x : T1. t2 : T1 T2 (S-TRANS) S <:T t : T T t : T 1 11 12 2 11 (T-APP) t1 t2 : T12 t : S S <:T T <: Top (S-TOP) (T-SUB) t : T
T <: S S <: T 1 1 2 2 (S-ARROW) S1 S2 <: T1 T2 Records syntactic forms Evaluation Rules extends i 1..n t ::= …. Terms: {li=vi }. lj vj(E-ProjRCD) i 1..n {li=ti } record t t’ t.l projection t.l t’.l (E-Proj}
v ::= …. Values: tj t’j (E-Tuple) i 1..n {li=vi } records {l =v i 1..j-1, l =t i j..n} {l =v i 1..j-1,l =t’,l =t k j+1..n} T ::= …. types: i i i i i i j j k k i 1..n New subtyping rules {li:Ti } record type
typing rules i 1..n+k i 1..n {li:Ti } <: {li:Ti } (S-RCDWIDTH) For each i t : T i i (T-Tuple) i 1..n i 1..n For each i S <: T {li=ti } : { li: Ti } i i (S-RCDEPTH) i 1..n i 1..n {li:Si } <: {li:Ti } t: { l : T i 1..n } i i (T-Proj)
t.lj : Tj {k :S j 1..n } is a permutation of {l :T i 1..n } j j i i (S-RCDPERM) j 1..n i 1..n {kj:Sj } <: {li:Ti } Example {x:Nat, y:Nat } <: {x:Nat} (S-RCDWIDTH) 0: Nat 0: Nat (T-Tuple) {x=0, y=0} : S={ x: Nat, y: Nat }
{x=0, y=0}: S S <:{x : Nat} (T-SUB) r : T’ = {x: T=Nat} (T-VAR) r : {x: Nat} r : T’ = {… x: T …} (T-Proj)
r : {x: Nat} r.x : T (T-ABS)
r : {x: Nat}. r.x : {x: Nat} T {x=0, y=0}: {x : Nat} (T-APP) (r : {x: Nat}. r.x) {x=0, y=0 } : T Properties of the type system(15.3)
• Uniqueness of types • Linear time type checking • Type Safety – Well typed programs cannot go wrong • No undefined semantics • No runtime checks – If t is well typed then either t is a value or there exists an evaluation step t t’ [Progress] – If t is well typed and there exists an evaluation step t t’ then t’ is also well typed [Preservation] Upcasting (Information Hiding)
• Special case of ascription
t: S S <: T (T-SUB)
t : T (T-ASCRIBE)
t as T: T Downcasting • Generate runtime assertion • But the typechecker can assume the right type
t : S (T-DOWNCAST) t as T : T v as T v (E-ASCRIBE) v :T (E-DOWNCAST) v as T v Progress is no longer guaranteed Can replace downcasts by dynamic type check
t1 : S , x: T t2 : U t3 : U (T-TYPETEST) if t1 in T then x t2 else t3 : U v :T (E-TYPETESTT) if v in T then x t2 else t3 [x v] t2 v :T (E-TYPETESTF) if v in T then x t2 else t3 t3 Downcasting vs. Polymorphism
• Downcasting is useful for reflection • Polymorphism saves the need for downcasts in most cases – reverse : X: list X list X • Polymorphism leads to shorter and more secure code • Polymorphism can have better performance • Downcasting complicates the runtime system • Polymorphism complicates language definition • The interactions between polymorphism and subtyping complicates type checking/inference – Irrelevant for Java Variants Modified syntactic forms t ::= …. Terms:
v ::= …. Values:
ti t’i (E-VARIANT)
i 1..n case (
t t’ i 1..n i 1..n case t of
t ::= …. Terms: i 1..n i 1..n +k
For each i , xi :Ti ti : T t :
S <: T (S-List) List S <: List T References
S <: T T <: S (S-Ref) ref S <: ref T Arrays
S <: T T <: S (S-Array) Array S <: Array T
S <: T (S-ArrayJava) Array S <: Array T Base Types
Bool <: Nat (S-BoolNat) Coercion Semantics for Subtyping (15.6)
• The compiler can perform conversions between types – Sometimes at compile time • Subtyping is no longer transparent • Improve performance Summary
• Subtyping improves reuse • Tricky semantics • Complicates type checking/inference • Well understood for many language features