Presentation is loading. Please wait.

Presentation is loading. Please wait.

Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis.

Similar presentations


Presentation on theme: "Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis."— Presentation transcript:

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


Download ppt "Safe & Efficient Gradual Typing for TypeScript Aseem Rastogi University of Maryland, College Park Nikhil Swamy Cédric Fournet Gavin Bierman Panagiotis."

Similar presentations


Ads by Google