950 likes | 1.12k Views
The Ins and Outs of Gradual Type Inference. Aseem Rastogi Stony Brook University. Avik Chaudhuri Basil Hosmer Adobe Systems. Gradually Typed Code. e.g., a Flash application in ActionScript. Statically Typed Code fully annotated w ith static types. Dynamically Typed Code
E N D
The Ins and Outs of Gradual Type Inference Aseem Rastogi Stony Brook University Avik Chaudhuri Basil Hosmer Adobe Systems
Gradually Typed Code e.g., a Flash application in ActionScript Statically Typed Code fully annotated with static types Dynamically Typed Code missing annotations = dynamic types type casts
Evolution of Scripts to Programs in our experience, a fantasy Statically Typed “Program” Gradual Typing missing annotations = dynamic types by default, rather than as fallback incrementally adding annotations for performance Dynamically Typed “Script”
Annoying Trade-Off Can this trade-off be eliminated? Annotation Burden Performance Penalty
Our Vision of Evolution Process • Type Inference: Key Ingredient for Evolution Infer Types Partially Typed “Script” Partially Untyped “Program” Annotate / Restructure
Gradual Type Inference • Type Inference Algorithm for Gradually Typed Languages Our Contributions • Practical Motivation • Improve Performance of • Flash Applications programs should not break, even when run in arbitrary environments • Goal • Backward Compatibility must admit reasoning outside the static type system • Non Goal • Increase Safety / Eliminate Errors … by eliminating as many type casts as possible
A Gradually Typed Program function foo(n:Number) { var s = 0; var i = s; while(i < n) { s = s + i; i = i + 1; } return s; }
Gradual Typing: No Type Inference function foo(n:Number):* { var s:* = 0; var i:* = s; while(i < n) { s = s + i; i = i + 1; } return s; } Missing Type = Dynamic Type
Gradual Typing: No Type Inference function foo(n:Number):* { var s:* = ⟨Number ▷ *⟩ 0; var i:* = s; while(i < n) { s = s + i; i = i + 1; } return s; } < : (Number, Number) Boolean + : (Number, Number) Number Type Casts Missing Type = Dynamic Type
Gradual Typing: No Type Inference function foo(n:Number):* { var s:* = ⟨Number ▷ *⟩ 0; var i:* = s; while(⟨* ▷ Number⟩i < n) { s = s + i; i = i + 1; } return s; } < : (Number, Number) Boolean + : (Number, Number) Number Missing Type = Dynamic Type
Gradual Typing: No Type Inference function foo(n:Number):* { var s:* = ⟨Number ▷ *⟩ 0; var i:* = s; while(⟨* ▷ Number⟩i < n) { s = ⟨Number ▷ *⟩ (⟨* ▷ Number⟩ s+ ⟨* ▷ Number⟩ i); i = i + 1; } return s; } < : (Number, Number) Boolean + : (Number, Number) Number Missing Type = Dynamic Type
Gradual Typing: No Type Inference function foo(n:Number):* { var s:* = ⟨Number ▷ *⟩ 0; var i:* = s; while(⟨* ▷ Number⟩i < n) { s = ⟨Number ▷ *⟩ (⟨* ▷ Number⟩ s+ ⟨* ▷ Number⟩ i); i = ⟨Number ▷ *⟩ (⟨* ▷ Number⟩ i + 1); } return s; } < : (Number, Number) Boolean + : (Number, Number) Number Missing Type = Dynamic Type
Gradual Typing: No Type Inference Performance Penalty function foo(n:Number):* { var s:* = ⟨Number ▷ *⟩ 0; var i:* = s; while(⟨* ▷ Number⟩i < n) { s = ⟨Number ▷ *⟩ (⟨* ▷ Number⟩ s+ ⟨* ▷ Number⟩ i); i = ⟨Number ▷ *⟩ (⟨* ▷ Number⟩ i + 1); } return s; } Missing Type = Dynamic Type
Gradual Typing: Type Inference function foo(n:Number):Foo! { var s:S = 0; var i:I = s; while(i < n) { s = s + i; i = i + 1; } return s; } Unknown types represented as type variables, solved to static typeswhere possible, dynamic typeas fallback Missing Type = Unknown Type Missing Type = Dynamic Type
Architecture of Type Inference Program Annotated With Type Variables Compilation Program With Coercions Closure Computation Solutions of Type Variables as Types Flow Relation Over Types Solution Derivation
Coercions • … are of the form T1 ▷ T2 • “term of type T1flows into context of type T2” • T ▷ X is an inflow for type variable X • X ▷ T is an outflowfor type variable X
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = s; while(i < n) { s = s + i; i = i + 1; } return s; } Number ▷ S
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩s; while(i < n) { s = s + i; i = i + 1; } return s; } Number ▷ S S ▷ I
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩i < n) { s = s + i; i = i + 1; } return s; } Number ▷ S S ▷ I I ▷ Number
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S> (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = i + 1; } return s; } Number ▷ S S ▷ I I ▷ Number S ▷ Number
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩i + 1); } return s; } Number ▷ S S ▷ I I ▷ Number S ▷ Number Number ▷ I
Generating Coercions function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩ i + 1); } return ⟨S ▷ Foo!⟩ s; } Number ▷ S S ▷ I I ▷ Number S ▷ Number Number ▷ I S ▷ Foo!
Solving for Type Variables X Inflows Outflows
Solving in a Static Type System Precision L.U.B. G.L.B. Safety Solution(X) X Inflows Outflows
Solving in a Gradual Type System Precision L.U.B. Solution(X) X Inflows
Solving in a Gradual Type System Precision L.U.B. Solution(X) Recall: eliminating errors is a non-goal X Inflows
Solving for Type Variables function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩ i + 1); } return ⟨S ▷ Foo!⟩ s; } Number ▷ S S = Number S ▷ I I ▷ Number S ▷ Number Number ▷ I S ▷ Foo!
Solving for Type Variables function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩ i + 1); } return ⟨S ▷ Foo!⟩ s; } Number ▷ S S = Number S ▷ I I = Number ⨆ S = Number I ▷ Number S ▷ Number Number ▷ I S ▷ Foo!
Solving for Type Variables function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩ i + 1); } return ⟨S ▷ Foo!⟩ s; } Number ▷ S S = Number S ▷ I I = Number ⨆ S = Number I ▷ Number S ▷ Number Number ▷ I S ▷ Foo! Foo! = S = Number
Solving for Type Variables function foo(n:Number):Foo! { var s:S = ⟨Number ▷ S⟩ 0; var i:I = ⟨S ▷ I⟩ s; while(⟨I ▷ Number⟩ i < n) { s = ⟨Number ▷ S⟩ (⟨S ▷ Number⟩ s + ⟨I ▷ Number⟩ i); i = ⟨Number ▷ I⟩ (⟨I ▷ Number⟩ i + 1); } return ⟨S ▷ Foo!⟩ s; } Number ▷ S S = Number S ▷ I I = Number ⨆ S = Number Outflows ignored I ▷ Number S ▷ Number Number ▷ I S ▷ Foo! Foo! = S = Number
Annotated Program function foo(n:Number):Number { var s:Number = ⟨Number ▷ Number⟩ 0; var i:Number = ⟨Number ▷ Number⟩s; while(⟨Number ▷ Number⟩i < n) { s = ⟨Number ▷ Number⟩ (⟨Number ▷ Number⟩ s + ⟨Number▷ Number⟩i); i = ⟨Number ▷ Number⟩ (⟨Number ▷ Number⟩i + 1); } return ⟨Number ▷ Number⟩ s; }
Annotated Program: No Casts function foo(n:Number):Number { var s:Number = 0; var i:Number = s; while(i < n) { s = s + i; i = i + 1; } return s; }
Summarizing… Key Idea (1) Consider Only Inflows to Solve Type Variables
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); }
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } Boolean Number ▷ X Number Number ▷ X
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } Boolean Number ▷ X Number Number ▷ X X = ⊥ Number
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } Boolean Number ▷ X Number Number ▷ X X = ⊥ Number Unsound
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } Boolean Number ▷ X Number Number ▷ X X = * Number
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } Boolean Number ▷ X Number Number ▷ X Imprecise X = * Number
Type Inference for Higher Order Types var x:X = function(y:Number):Number { … }; If(b) { x = function(y:Boolean):Number { … }; x(true); } X = Boolean Number Boolean Number ▷ X Number Number ▷ X
Higher Order Types: Kinds Suppose that solution of X is of the form _ _ function type
Higher Order Types: Kinds Suppose that solution of X is of the form _ _ The kind of X under this structure isX? X!
Higher Order Types: Kinds Suppose that solution of X is of the form _ _ The kind of X under this structure isX? X! Infer X? and X! based on their inflows function applications of X
Higher Order Types: Kinds Suppose that solution of X is of the form _ _ “a kind for every type constructor” all parts of a higher-order type solved based on inflows ≈ naïve subtyping The kind of X under this structure isX? X! Infer X? and X! based on their Inflows
Type Inference for Higher Order Types Boolean Number ▷ X var x:X = function(y:Number):Number { … }; if(b) { x = function(y:Boolean):Number { … }; x(true); } Number Number ▷ X Number Number ▷ X? X! Boolean Number ▷ X? X! X?X! ▷ X
Type Inference for Higher Order Types Boolean Number ▷ X var x:X = function(y:Number):Number { … }; if(b) { x = function(y:Boolean):Number { … }; x(true); } Number Number ▷ X Boolean Number ▷ X? X! Number Number ▷ X? X! X?X! ▷ X Boolean ▷ X?
Type Inference for Higher Order Types Boolean Number ▷ X var x:X = function(y:Number):Number { … }; if(b) { x = function(y:Boolean):Number { … }; x(true); } Number Number ▷ X Boolean Number ▷ X? X! Number Number ▷ X? X! X?X! ▷ X Boolean ▷ X? X? ▷ Boolean Number ▷ X!
Type Inference for Higher Order Types Boolean Number ▷ X var x:X = function(y:Number):Number { … }; if(b) { x = function(y:Boolean):Number { … }; x(true); } Number Number ▷ X Number Number ▷ X? X! Boolean Number ▷ X? X! X?X! ▷ X Boolean ▷ X? X? ▷ Boolean Number ▷ X! X? ▷ Number