StrongScript: concrete types for TypeScript Gregor Richards Jan Vitek and myself Monday 23 March 15 1 StrongScript: ...the language Andreas has been dreaming about... Gregor Richards Jan Vitek and myself Monday 23 March 15 2 Scripting languages are not statically typed Monday 23 March 15 3 They are successful Monday 23 March 15 4 Can we improve them? Monday 23 March 15 5 Industry answer optional type systems Hack, Dart, TypeScript, … Surprising properties: types do not affect execution types are unsound Pragmatic benefits: IDE support Monday 23 March 15 6 ok bo tF ac e ou se Ha ck a Industry answer ed t optional type systems ref ac tor Hack, Dart, TypeScript, … nl ine so fP HP Surprising properties: types do not affect execution types are unsound 20 mi llio Pragmatic benefits: IDE support Monday 23 March 15 6 ok bo tF ac e Academia answer ou se Ha ck a Industry answer Racket, StrongTalk, … Surprising properties: types do not affect execution types are unsound Types affect execution Types are sound nl ine so fP HP ref Hack, Dart, TypeScript, … gradual type systems ac tor ed t optional type systems 20 mi llio Pragmatic benefits: IDE support Monday 23 March 15 Values are wrapped at dynamic/static boundaries: - statically-typed code can fail - runtime overhead 6 Why do I like types 1. Help with refactoring, IDE support, ... 2. In Java, at runtime x.f will always succeed if x is not null 3. In Java, x.f is compiled to a couple of machine instructions Monday 23 March 15 7 Why do I like types 1. Help with refactoring, IDE support, ... 2. In Java, at runtime x.f will always succeed if x is not null safety 3. In Java, x.f is compiled to a couple of machine instructions speed predictable execution time Monday 23 March 15 7 Why do I like types 1. Help with refactoring, IDE support, ... t r o h s ll 2. In Java, at runtime x.f will always succeed iffa x is not null safety a u rad e p l ty g nd m e t s y s a 3. In Java, x.f is compiled to a couple of machine instructions l a h t o b Monday 23 March 15 n o i t p o speed predictable execution time 7 Our plan Allow programmers to chose: lightweight type annotations should not introduce dynamic errors in well-tested dynamic programs if programmers select more stringent checks, they should have the usual type-errors and improved performance properties. Monday 23 March 15 8 Background: TypeScript Monday 23 March 15 9 TypeScript • Types are hints to the programming environment, not to the code generator • Enables some type-checking, support IDE features name completion, semi-automated refactorings • Lack of type preservation seen as necessary tradeoff • Support only a small subset of JavaScript idioms • No attempt to provide guarantees on other dynamic behaviours Monday 23 March 15 s e c a f r e t s n i e l , s u e d s o s a cl nd m a 10 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} s g dist(p: Point) { ... } n i n r } a w class CPoint extends Point { o n constructor (public color:String, x:number, y:number){ super(x,y); } h t i dist(p: CPoint) { ...p.color... } w s } le pi m o c var o:Pt = new Point(0,0); e var c:CPoint = new CPoint("Red",1,1); d o c function pdist(x:Point, y:Point) { x.dist(y); } s i pdist( c, o ); h t var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 11 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} dist(p: Point) { ... } } class CPoint extends Point { constructor (public color:String, x:number, y:number){ super(x,y); } dist(p: CPoint) { ...p.color... } } var o:Pt = new Point(0,0); var c:CPoint = new CPoint("Red",1,1); function pdist(x:Point, y:Point) { x.dist(y); } pdist( c, o ); var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 11 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} dist(p:interfaces Point) { ... } declare properties and methods } extends has only documentation purposes class CPoint extends Point { constructor (public color:String, x:number, y:number){ super(x,y); } subtyping is structural dist(p: CPoint) { ...p.color... } } var o:Pt = new Point(0,0); var c:CPoint = new CPoint("Red",1,1); function pdist(x:Point, y:Point) { x.dist(y); } pdist( c, o ); var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 12 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} dist(p: Point) { ... } } class CPoint extends Point { constructor (public color:String, x:number, y:number){ super(x,y); } dist(p: CPoint) { ...p.color... } } var o:Pt = new Point(0,0); var c:CPoint = new CPoint("Red",1,1); functionboth pdist(x:Point, x.dist(y); } classes arey:Point) subtype{ of the interfaces pdist( c, o ); above dist is overridden covariantly var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 13 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { Implicit cast of Pointx:number, to Pt, allowed structural subtyping. constructor (public publicby y:number){} dist(p: Point) { ... } pdist calls dist at static type Point, but is invoked with a CPoint: } the CPoint compiler allows the {call class extends Point constructor (public color:String, y:number){ super(x,y); } at runtime the access of p.color x:number, returns undefined. dist(p: CPoint) { ...p.color... } } var o:Pt = new Point(0,0); var c:CPoint = new CPoint("Red",1,1); function pdist(x:Point, y:Point) { x.dist(y); } pdist( c, o ); var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 14 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} dist(p: Point) { ... } } class CPoint extends Point { constructor (public color:String, x:number, y:number){ super(x,y); } dist(p: CPoint) { ...p.color... } } Any type can be converted implicitly to any. Anyo:Pt method be invoked on an any reference. var = new can Point(0,0); var = new CPoint("Red",1,1); An c:CPoint any reference can be converted implicitly to any function pdist(x:Point, y:Point) { x.dist(y); } pdist( c, o ); other type. var q:any = new CPoint("Red",1,1); var c = q.dist( o ); var b = o.dist( q ); function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 15 interface P { x: number; } interface T { y: number; } interface Pt extends P { y: number; dist(p: Pt); } class Point { constructor (public x:number, public y:number){} dist(p: Point) { ... } } class CPoint extends Point { constructor (public color:String, x:number, y:number){ super(x,y); } dist(p: CPoint) { ...p.color... } } var o:Pt = new Point(0,0); var c:CPoint = new CPoint("Red",1,1); function pdist(x:Point, y:Point) { x.dist(y); } pdist( c, o ); var q:any = new CPoint("Red",1,1); An var c = q.dist( o ); var b = o.dist( q ); unchecked explicit cast. function getc(x:CPoint) { return x.color }; getc( <CPoint>o ); Monday 23 March 15 16 Summary + plan Monday 23 March 15 17 Them... any C trace preserving? Gradual any, W(any) C, W(any) no TypeScript any any yes Monday 23 March 15 18 ...and Us any C trace preserving? Gradual any, W(any) C, W(any) no TypeScript any any yes any at optional types StrongScript any !C C enable efficient compilation Monday 23 March 15 19 Programming with concrete types Monday 23 March 15 20 StrongScript 1. Start from TypeScript 2. Add the !C type for each class name C 3. Three kinds of type annotations: concrete types dynamic type optional types Monday 23 March 15 denoted !C any C typechecks as C any C points to objects of type C any any 21 var p:any = { x=3; z=4 } var f:any = func (p) { if (p.x < 10) return 10 else return p.distance() } f(p) Monday 23 March 15 22 var p:any = { x=3; z=4 } var f:any = func (p) { if (p.x < 10) return 10 else return p.distance() } f(p) Evaluates to 10. Monday 23 March 15 22 var p:any = { x=3; z=4 } var f:any = func (p) { if (p.x < 10) return 10 else return p.distance() } f(p) Evaluates to 10. now the programmer documents his expectations about the argument of f... Monday 23 March 15 22 class Point { constructor(public x, public y){} dist(p) { return ... } } var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.distance() } Monday 23 March 15 23 class Point { constructor(public x, public y){} dist(p) { return ... } } Correct. var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.distance() } Monday 23 March 15 23 class Point { constructor(public x, public y){} dist(p) { return ... } } Correct. var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.distance() } Static type error. Monday 23 March 15 23 class Point { constructor(public x, public y){} dist(p) { return ... } } Correct. var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.distance() } Static type error. still flexible get local type checking, IDE completion, ... Monday 23 March 15 23 class Point { constructor(public x, public y){} dist(p) { return ... } } var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.dist() } var s:!Point = new Point(5,6); f(s); Monday 23 March 15 24 f was typechecked against Point, so we can safely pass a real Point class Point { constructor(public x, public y){} dist(p) { return ... } } var p:Point = { x=3; z=4 } var f:any = func (p:Point) { if (p.x < 10) return 10 else return p.dist() Correct. } var s:!Point = new Point(5,6); f(s); Evaluates to 10. Monday 23 March 15 24 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" Monday 23 March 15 25 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" DYNAMIC ERR: type mismatch Monday 23 March 15 25 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" DYNAMIC ERR: type mismatch instances of classes protect themselves Monday 23 March 15 25 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" t.dist({x=1;y=2}); var fact = func(x:!number) {return ...:!number} var u:TypedPoint = { dist = function(p) {...} } var n:!number = fact(u.dist(p)) Monday 23 March 15 26 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" t.dist({x=1;y=2}); Correct var fact = func(x:!number) {return ...:!number} var u:TypedPoint = { dist = function(p) {...} } var n:!number = fact(u.dist(p)) Monday 23 March 15 26 class TypedPoint { constructor(public x:!number, public y:!number){} dist(p) { return ... :!number } } var t:!TypedPoint = new TypedPoint (1,2) (<any>t).x = "o" t.dist({x=1;y=2}); Correct var fact = func(x:!number) {return ...:!number} var u:TypedPoint = { dist = function(p) {...} } var n:!number = fact(u.dist(p)) u.dist(p) has type !number Monday 23 March 15 26 Guarantees g n i t u c e x e y l n o e s i r a s r e o r d r o e c e d m e i t p y t run y l l a n o i t p o r o y l l a dynamic k a e r b t o n s e o d n o i t a t o n n a e p y t l a n o i m t a r p g o o r n a p g c i m a n addin y d t c a corre d e n e h t g n e r t s e b n a c , m a r g o r s p e d p e y t p y e t t e y l r l c a n n o o i c t h p t i o w y l s e t e e p l y p t m n o o i t p ac o l l a g n i c a l p e r y b Monday 23 March 15 27 Implementation and evaluation Monday 23 March 15 28 StrongScript compilation strategy StrongScript is compiled to plain JS code Dynamic type-checking code is compiled into JS code Intrinsics improve performance on supporting interpreters Monday 23 March 15 29 Compiling classes As in TypeScript, classes are compiled with the class pattern: = 42; Also support for modules, as in TypeScript. Monday 23 March 15 30 Dynamic type checks StrongScript inserts dynamic checks at downcasts: • primitive types are checked with the typeof operator; • classes are checked with the instanceof operator. Contrast with TypeScript, which erases all type and performs no checks at run-time. By definition, optional types require no checks. If optional blame tracking is enabled, values at optional types are wrapped and checked lazily. Monday 23 March 15 31 Type protection for classes Fields are hidden, an accessor allows read and write access mediated by a checking function. Fields accessed in an object with a statically-declared type, the accessor is bypassed. Each method in a class is generated as two methods: one to be used by typed clients, one to be used by untyped clients. Monday 23 March 15 32 Target StrongScript output is idiomatic JavaScript, extended with • checks for static types • intrinsics to explicitly specify the memory layout (can also guide boxing/unboxing) ) s s e r g o r p n i l p m i 8 V ( S J e fl s f t u c r e T j f b o o n g o n i i s s n u e t y l x i e v r a e u h o s y k b r a d m h c n e b supporte n o d e v r e s b o p u d spee Monday 23 March 15 33 Industry answer Academia answer optional type systems gradual type systems Hack, Dart, TypeScript, … Racket, SmallTalk, … Surprising properties: types do not affect execution types are unsound Types affect execution Types are sound Pragmatic benefits: IDE support Values are wrapped at dynamic/static boundaries: - statically-typed code can fail - runtime overhead Monday 23 March 15 34 y answer StrongScript Academia Static types are preserved Dynamism of JavaScript preserved ype systems TypeScript, … operties: ot affect execution nsound enefits: t Monday 23 March 15 Optional types are trace preserving (enabling program evolution) gradual type Efficient and predictable implementation for static types. Types affect ex Types are soun o p o t n o n o i t a t n e l ...imp . . . s s e r g o r f V8 in p Racket, SmallT Values are wra dynamic/st - statically-type - runtime overh 34 Monday 23 March 15 35
© Copyright 2024