StrongScript: concrete types for TypeScript

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