Download presentation
Presentation is loading. Please wait.
Published byClaribel Pitts Modified over 9 years ago
1
Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis Vekris (Microsoft Research) (Oracle) (UCSD)
2
Gradual Typing Combines benefits of static and dynamic typing 2 Statically-typed fragment Dynamically- typed fragment Dynamic type any Runtime checks mediate interaction Static type errors Performance Typed interface documentation Rapid prototyping Flexibility
3
TypeScript, Dart, Closure, Flow (we focus on TypeScript) Increase programmer productivity (static type errors, intellisense, code refactoring, modularity …) Types don’t get in the way of good programmers (retain flavor of programming in JavaScript) 3 Increasing Adoption in Industry Mainly for JavaScript
4
TypeScript is Intentionally Unsound For All Its Dynamic Idioms, Typing JavaScript is Hard ! Unsound typing rules to support supposedly common idioms (covariant array subtyping, covariant function arguments, …) Types are uniformly erased during compilation (lightweight compilation, no runtime performance cost, …) (unchecked runtime casts, types don’t guarantee anything) 4
5
Programmers Cannot Rely On Types 5 private parseColorCode (c:string) { if (typeof c !== "string") return -1; … } Snippet from TouchDevelop, a large TypeScript Development Tools can’t rely on types Refactoring, compiler optimizations, etc. are not safe
6
6 Can we design a gradual type system that is: Safe Efficient Supports idiomatic TypeScript/JavaScript We present Safe TypeScript
7
Safe TypeScript is Sound TypeScript is Intentionally Unsound Standard variance for arrays and function arguments Sound treatment of JavaScript this Careful separation of nominal and structural types Easy local rewriting of unsound idioms in 120,000 line corpus TypeScript has unsound typing rules to support common idioms 7
8
Safe TypeScript is Sound TypeScript is Intentionally Unsound Safe TypeScript guarantees type safety Combination of static checking and runtime checks Runtime-type-information (RTTI) based gradual typing Efficiency using two new notions of partial erasure Runtime overhead of only 15% for bootstrapping Safe TypeScript 6.5% for typed Octane benchmarks TypeScript uniformly erases all types making uses of any unsafe 8
9
9 Formalized core of Safe TypeScript, proven sound class C, interface I, {M;F}, number, any, Erased t Implemented in a branch of TypeScript v0.9.5 Can be invoked with --safe command line flag Evaluated on 120,000 lines of code Bootstrapped Safe TypeScript compiler, New TypeScript compiler, Octane Our Contributions
10
10 Safe TypeScript Tour Overview of RTTI-based Gradual Typing Values carry Run Time Type Tags consistent with their contents Dynamically-typed code instrumented to respect RTTI tags Invariant: v : [| v.tag |] Object with 3 fields and type tag f = 2 g = "s" h = true tag = {f:number; g:string}
11
interface Point { x:number } function g(p:Point) { p.x = p.x + 1; } function f() { var p:Point = { x = 0 }; g(p); } 11 Compiles unchanged No runtime checks No tagging ! Previous systems tag eagerly RTTI Tagging in Safe TypeScript On-demand and Differential Safe TypeScriptJavaScript
12
12 RTTI Tagging in Safe TypeScript On-demand function g(p:any) { p.x = p.x + 1; } function f() { var p:Point = { x = 0 }; g(p); } function f() { var p = { x = 0 }; g(shallowTag(p, Point)); } shallowTag(x,t) = x.tag := combine(x.tag, t); x Safe TypeScriptJavaScript Add RTTI when types lose precision
13
13 RTTI Tagging in Safe TypeScript Differential shallowTag(x,t) = x.tag := combine(x.tag, t); x interface 2dPoint extends Point { y:number } function h(p:any) {.. } function g(p:Point) { h(p); } function f() { var p:2dPoint = { x = 0; y = 0 }; g(p); } function g(p) { h(shallowTag(p, Point)); } function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } Safe TypeScriptJavaScript Add Minimum Required RTTI
14
14 RTTI Tagging in Safe TypeScript shallowTag(x,t) = x.tag := combine(x.tag, t); x function g(p) { h(shallowTag(p, Point)); } function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } JavaScript Add Minimum Required RTTI x = 0 y = 0
15
15 RTTI Tagging in Safe TypeScript shallowTag(x,t) = x.tag := combine(x.tag, t); x function g(p) { h(shallowTag(p, Point)); } function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } JavaScript Add Minimum Required RTTI x = 0 y = 0 tag = {y:number} x = 0 y = 0
16
16 RTTI Tagging in Safe TypeScript shallowTag(x,t) = x.tag := combine(x.tag, t); x function g(p) { h(shallowTag(p, Point)); } function f() { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } JavaScript Add Minimum Required RTTI x = 0 y = 0 tag = {x:number; y:number} x = 0 y = 0 tag = {y:number} x = 0 y = 0
17
Differential Subtyping t1 d d = 0 | t d is loss in precision that must be captured in the RTTI 17 Differential Subtyping Technical Device for On-Demand and Differential Tagging
18
t 0 {x:number;y:number} {y:number} {x:number;y:number} Primitive RTTI Aware: number 0 18 Differential Subtyping t1 d d is loss in precision
19
Γ |- e : t2 ~> e’ t2 d Γ |- e : t1 ~> shallowTag(e’, d) 19 T-Sub Differential Subtyping t1 d d is loss in precision
20
20 Instrumentation of Dynamically Typed Code function g(p:any) { p.x = "boom" ; } function f() { var p:Point = { x = 0 }; g(p); assert(typeof p.x === "number"); } function f() {.. } function g(p) { write(p, "x", "boom" ); } write(o,f,v) = let t = o.tag; o[f] = check(v, t[f]); (Recall that f tags p with type Point ) // Fails Safe TypeScriptJavaScript
21
21 Differential Tagging Useful, But Not Ideal function g(p) { return p.x; } function f(p) { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } Safe TypeScriptJavaScript function g(p:Point) { return p.x; } Unnecessary shallowTag function f() { var p:2dPoint = { x = 0; y = 0 }; g(p); }
22
22 Reason: Need Conservative Tagging Previous gradual type systems: t any for all static types t Incurs tagging even for statically typed code Relaxing it opens opportunities for sound type erasure
23
A new type modality: Erased t Erased t cannot be cast to any Statically a t but may not have an RTTI at runtime 23 Erased Types Programmer-controlled Tagging Behavior
24
t1 d t1 0 Erased t <\: any 24 Subtyping for Erased Types // Zero delta // Ensure full erasure is safe
25
25 Erased Types Example: No Tagging Safe TypeScriptJavaScript function g(p) { return p.x; } function f(p) { var p = { x = 0; y = 0 }; g(shallowTag(p, { y:number })); } function g(p:Point) { return p.x; } Unnecessary shallowTag function f() { var p:2dPoint = { x = 0; y = 0 }; g(p); }
26
26 Erased Types Example: No Tagging function g(p) { return p.x; } function f(p) { var p = { x = 0; y = 0 }; g(p); } Safe TypeScriptJavaScript function g(p:Erased Point) { return p.x; } function f() { var p:2dPoint = { x = 0; y = 0 }; g(p); } // No tagging Recall shallowTag for non-erased types
27
27 Erased Types Example: No Tagging function f(p) { var p = { x = 0; y = 0 }; g(p); } Safe TypeScriptJavaScript function g(p:Erased Point) { return h(p); } function f() { var p:2dPoint = { x = 0; y = 0 }; g(p); } // No tagging function h(p:any) {.. } Static Type Error
28
Obey a fully static type discipline (Sound type erasure, type abstraction, …) (Loss in expressiveness: not all code can be turned dynamic) Other advantages of Erased types Working with external libraries that may not have RTTI Adding new features to the type system (e.g. Polymorphism) See our paper for more details 28 Erased Types
29
29 Soundness Theorem: Forward Simulation Checks introduced by Safe TypeScript: Catch any dynamic type error Do not alter the semantics of type safe code Tag heap evolution invariant
30
Implemented in a branch of TypeScript v0.9.5 Invoke our type checker with --safe flag 10,000 Lines of Code Compiles to plain JavaScript (with instrumented checks) (recursive interfaces, inheritance, overloading, generics, arrays, external libs, …) 30 Safe TypeScript Implementation Open Source on Github
31
Bootstrapping Safe TypeScript 90,000 Lines of Code, heavily class based, carefully annotated Number of Errors Covariant method arguments 130 Variable scoping128 Potential unsound use of this 52 Bivariant array subtyping98...… Total478 Static Type Errors found in Safe TypeScript Code
32
Bootstrapping Safe TypeScript 90,000 Lines of Code, heavily class based, carefully annotated Static Type Errors found in Safe TypeScript Code All cases in one file using visitor pattern, easily rewritten Sloppy use of var declarations, easily fixed Projection of methods, easily fixed by making them functions Fixed by introducing array mutability qualifiers Number of Errors Covariant method arguments 130 Variable scoping128 Potential unsound use of this 52 Bivariant array subtyping98...… Total478
33
Bootstrapping Safe TypeScript 90,000 Lines of Code, heavily class based, carefully annotated 478 Static type errors 26 failed runtime downcasts; 5 in our own code ! 15% runtime overhead of type safety
34
Octane Benchmarks (6 / 17) 22x (ave.) and 72x (max.) overhead with no type annotations Down to 6.5% after adding type annotations No overhead for statically-typed code Found a variable scoping bug in navier-stokes It has since been fixed Efficiency conditioned on precise type inference TypeScript quite conservative
35
Nominal handling of prototype-based classes Sound handling of this Abstraction theorem for Erased { } Zero-subtyping to avoid object identity issues More experiments (TypeScript v1.1, Octane benchmarks, Different tagging schemes) 35 Also in the paper …
36
When to use Safe TypeScript ? For mature TypeScript projects, improved code quality Good in development setting for finding early bugs Baseline for JS analyses focusing on deeper properties 36 Safe TypeScript Summary Safe & Efficient Gradual Typing for TypeScript Significant value for type annotations at a modest cost (runtime checks at least during development and testing) Significant value for type annotations at a modest cost (runtime checks at least during development and testing) Give it a go !
37
37 interface Point {..} interface 2dPoint {..} Erased Types Example: Type Abstraction function g(p:Point) { write(p, "y", 3); } function f() {..} RTTI of p at write is {y:number} write succeeds: abstraction violation function g(p:Point) { ( p).y = 3; } function f() { var p:2dPoint = {x = 0;y = 0}; g(p); } Safe TypeScriptJavaScript
38
38 function g(p:Point) { ( p).y = 3; } function f() { var p:2dPoint = {x = 0;y = 0}; g(p); } interface Point extends Erased {..} interface 2dPoint extends Point {..} Static Type Error Erased Types Example: Type Abstraction Safe TypeScriptJavaScript
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.