<<

Chapter 15 Benjamin Pierce Types and Programming Languages Varieties of 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

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 (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: as T tagging i 1..n case t of

  •  ti case

    v ::= …. Values: as T tagged value T ::= …. types: i 1..n

  • type of variants Evaluation Rules extends 

    ti  t’i (E-VARIANT) as T as T

    i 1..n case ( as T) of

  •  ti  [xjv] tj (E-CaseVariant)

    t  t’ i 1..n i 1..n case t of

  •  ti  case t’ of
  •  ti (E-CASE) Modified Type rules for Variants Modified syntactic forms New subtyping rules

    t ::= …. Terms: i  1..n i  1..n +k <: (S-VARIANTWIDTH) as T tagging i 1..n case t of

  •  ti case For each i S <: T i i (S-VARIANTDEPTH) v ::= …. Values: i  1..n i  1..n <: as T tagged value T ::= …. types: type of variants i i is a permutation of modified typing rules j j i i (S-VARIANTPERM) <: tj : Tj j j i i i 1..n (T-VARIANT)  as
  • : < lj= Tj >

    For each i , xi :Ti ti : T  t : i i (T-CASE) i 1..n case t of

  •  ti : T Lists

    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