CSE 230: Winter 2008 Principles of Programming Languages Ocaml/HW #3 Q-A Session Push deadline = Mar 10 Session Mon 3pm? Lecture 15: Type Systems Ranjit Jhala UC San Diego Why Typed Languages? Development Type checking catches mistakes, less debugging Typed signatures are a powerful basis for design Typed signatures enable fast, separate compilation Maintenance Types act as checked specifications Types can enforce abstraction Execution Static checking eliminates dynamic checking Compiler uses types to generate better code Why Not Typed Languages? Static types impose constraints on programmer Some valid programs might be rejected Usually they can be made well-typed easily Dynamic safety checks can be slow Array bounds checking has performance penalty Automatic memory management, gc may be slow
Properties of Type Systems Should be algorithmically checkable Typing rules should be transparent Easily show why program not well-typed Not always the case Why Formal Type Systems? Informal descriptions in reference manuals Careful analysis to avoid false claims of safety Formal type system = precise spec of checker Allows formal proofs of type safety Informal knowledge of principles useful Understand errors and limitations, build analyses Formalizing a Type System 1. Syntax Expressions (programs) Types 2. Static semantics (aka typing rules) Define typing judgments and derivation rules 3. Dynamic semantics (aka operational semantics) Define evaluation judgment and its derivation rules 4. Type soundness Relate static and dynamic semantics Typing Judgments Judgments = statements about entities Validjudgements (universally true): ² J Provable judgements: ` J Common typing judgment: Γ ` e : τ e is an expression of type τ if free variables have types given by Γ Γ : set of type assignments for free vars Assignments for bound variables irrelevant E.g, x : int, y : int ` x + y : int
Typing Rules Used to derive typing judgments. Typing Derivations or proofs of typing judgments Examples: Γ `1: int x:τ Γ Γ ` x:τ x:int ` x:int x:int ` 1:int x:int `x:int x:int `x+1:int x:int ` x+(x+1): int Γ ` e : τ denotes judgement has a derivation Γ ` e 1 : int Γ ` e 2 : int Γ ` e 1 + e 2 : int Type checking: given Γ, e, τ find derivation Type inference: given Γ, e find type τ and derivation Proving Type Soundness Define what it means for a value to have a type: v k τ k (e.g. 5 k int k, true k bool k) Define what it means for an expr to have a type e k τ k iff v. (e v v k τ k) Type soundness: If `e : τ then e k τ k i.e. If `e : τ and e v then v k τ k Implies safe execution as result of unsafe execution is not in kτk Plan I Formalize first-order type systems: Simple types (integers and booleans) Function types (simply typed λ-calculus) Structured types (products/records and sums) Imperative types (references and exceptions) Recursive types (lists, trees) Subtypes Most common languages
Plan 2 Then second-order order type systems: With type variables Polymorphism Abstract types Formalize first-order type systems Simple types (integers and booleans) Function types (simply typed λ-calculus) Structuredtypes (products and sums) Recursive types (lists, trees) Imperative types (pointers and exceptions) Simply-Typed λ-calculus: Syntax Terms e ::= x λx:τ. e e 1 e 2 n e 1 + e 2 iszero e true false not e if e 1 then e 2 else e 3 Types τ ::= int bool τ 1 τ 2 τ 1 τ 2 is the function type associates to the right Formalshave typing annotations This language is also called F 1 Static Semantics of F 1 The typing judgment Γ ` e : τ The typing rules x:τ Γ Γ ` x:τ Γ ` e:τ τ Γ` e :τ Γ ` e e :τ Γ, x:τ ` e: τ Γ ` λx:τ.e : τ τ
Static Semantics of F 1 More typing rules Γ ` e 1 : int Γ ` e 2 : int Γ ` n: int Γ ` e 1 + e 2 : int Γ ` true: bool Γ ` e 1 : bool Γ ` e : bool Γ ` not e: bool Γ ` e 2 : τ Γ ` e 3 : τ Γ ` if e 1 then e 2 else e 3 : τ Typing Derivation in F 1 Consider: λx:int.λb: bool. if b then f x else x With the typing assignment f : int int Γ ` b:bool Γ ` f :int int Γ ` x :int Γ ` f x:int Γ ` x:int f:int int, x:int, b:bool ` if b then f x else x : int bool int f:int int, x:int` λb : bool. if b then f x else x : int bool int f:int int ` λx:int.λb : bool. if b then f x else x : int bool int where Γ is short for f : int int, x : int, b : bool Type Checking in F 1 Type checking is easy: Typing rules are syntax directed One rule per kind of expression Typing rules are compositional Local variables are annotated with types In fact, type inference is also easy Note: without annots, exprs lack unique types: `λx. x : int int ` λx. x : bool bool Typability Q: Is an untyped expression typable in env. Γ? Can erase types from expressions: erase(x) = x erase(e 1 e 2 ) = erase(e 1 ) erase(e 2 ) erase(λx: τ. e) = λx. erase(e) Q: Given e, Γ are there e and τ such that: erase(e )=e e and Γ ` e :τ? Example: λx.x is typable in the empty environment in more than one way
Next Relating Static Semantics (Types) to Dynamic Semantics (Operational) Operational Semantics of F 1 Judgment: Values e v v ::= n true false λx:τ. e plus evaluation rules... Operational Semantics of F 1 Call-by-value evaluation rules λx:τ.e λx:τ.e e 1 λx:τ.e 1 e 2 v 2 [v 2 /x]e 1 v e 1 e 2 v n n e 1 true e 2 v e 1 n 1 e 2 n 2 n=n 1 +n 2 e 1 +e 2 1 2 n e 1 false e 3 v if e 1 then e 2 else e 3 v if e 1 then e 2 else e 3 v Type Soundness for F 1 Theorem: If `e : τ and e v then `v : τ aka subject reduction or type preservation Proof? by induction on e? fails due to [v 2 /x]e 1 in evaluation of e 1 e 2 Same problem with induction on `e : τ by induction on τ? fails as e 1 has a bigger type than e 1 e 2 by induction on e v Successfully addresses issue of [v 2 /x]e 1
Type Soundness Proof Key case: e 1 λx:τ.e 1 e 2 v 2 e 1 e 2 v [v 2 /x]e 1 v And, by inversion on type derivation for e 1 e 2 Γ ` e 1 :τ 2 τ Γ` e 2 :τ 2 Γ ` e 1 e 2 :τ RTP ` v : τ From IH on e 1 we have,, x : τ 2 ` e 1 : τ From IH on e 2 we have ` v 2 : τ 2 Need to infer that ` [v 2 /x]e 1 : τ need substitution lemma: If Γ,x:τ ` e : τ and Γ ` e : τ then Γ ` [e /x]e : τ Significance of Type Soundness Evaluated result has same type as expression Theorem does not say that: 1. The evaluation ation never er gets stuck applying a non-function, add non-integers 2. The evaluation terminates Though h both are true for F 1 1. Non-stuck: via small-step semantics 2. Termination: hw exercise Small-Step Step Contextual Semantics for F 1 Redexes r ::= n 1 + n 2 if b then e 1 else e 2 (λx:τ.e 1 ) v 2 Contexts H ::= H+e 2 n 1 + H if H then e 1 else e 2 He 2 (λx:τ. e 1 ) H Local reduction rules n 1 + n 2 n 1 plus n 2 if true then e 1 else e 2 e 1 if false then e 1 else e 2 e 2 (λx:τ. e 1 ) v 2 [v 2 /x]e 1 Global reduction rule if r E then H[r] H[e] Contextual Semantics for F 1 Unique Decomposition lemma: If ` e : τ and e is not a value then: 1. there exist unique H and r such that e = H[r] Any well-typed expression can be decomposed 2. there exists τ such that `r : τ redex is well-typed 3. there exists e such that r e and `e : τ local reduction is type preserving 4. for any e, ` e : τ implies ` H[e ] : τ Type preserved if redex substituted with expr of same type So: A well-typed non-value can make type preserving progress
Preservation and Progress Type preservation theorem: If `e : τ and e e then `e : τ Follows from decomposition lemma Progresstheorem: If `e : τ and e is non-value then there exists e s.t. e can progress: e e In english: 1. well-typed expression can make progress 2. type is preserved i.e. result of progress is well-typed 3. Goto 1: (progress continues, i.e. expr. never stuck) An Alternative: Explicit Errors Same results via big-step semantics: introduce an error value wrong Result (meaning) of stuck expressions Prove theorem: well-typed programs don t go wrong (i.e never evaluate to wrong ) Note: Types = abstract interpretation static ti approximation of dynamic values