Dependent
Sponsored Links
This presentation is the property of its rightful owner.
1 / 90

Dependent Types for JavaScript PowerPoint PPT Presentation


  • 72 Views
  • Uploaded on
  • Presentation posted in: General

Dependent Types for JavaScript. Ravi Chugh Ranjit Jhala. University of California, San Diego. David Herman. Mozilla Research. Dependent Types for JavaScript. Why. ?. Pervasive Used at Massive Scale. Why Add Types?. var x = {}; x.f ; x.f.f ;.

Download Presentation

Dependent Types for JavaScript

An Image/Link below is provided (as is) to download presentation

Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author.While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server.


- - - - - - - - - - - - - - - - - - - - - - - - - - E N D - - - - - - - - - - - - - - - - - - - - - - - - - -

Presentation Transcript


DependentTypes for JavaScript

Ravi ChughRanjitJhala

University of California, San Diego

David Herman

Mozilla Research


DependentTypes for JavaScript

Why

?

Pervasive

Used at Massive Scale


Why Add Types?

var x = {};

x.f;

x.f.f;

produces undefined rather than error…

… but this raises TypeError


Why Add Types?

var x = {};

x.f;

x.f.f;

There Are Run-time Errorsreading from undefined, applying non-function values, …

Worse: Browsers Hide Them!


Why Add Types?

Prevent Errors

Prevent the Unexpected


Okay, But Who Cares?

ProgrammersJSLint, Closure Compiler, TypeScript, Dart

Browser VendorsCompete based on performance, security, reliability

Standards CommitteesActively evolving JavaScript and Web standards


DependentTypes for JavaScript

Why

?

Isn’t the Language Terrible?


JavaScript

scope manipulation

implicit global object

var lifting

‘,,,’ == new Array(4)


JavaScript

scope manipulation

prototypes

objects

implicit global object

lambdas

type-tests

var lifting

‘,,,’ == new Array(4)


JavaScript

scope manipulation

“The Good Parts”

prototypes

objects

implicit global object

lambdas

type-tests

var lifting

‘,,,’ == new Array(4)


JavaScript

“The Good Parts”

Our Approach

Key Idea:

Use Logic!

PriorTypeSystems


JavaScript

“The Good Parts”

DJS

Dependent JavaScript


Outline

  • Motivation

  • Our Approach: Logic!

  • Evaluation


typeof true // “boolean”

typeof 0.1 // “number”typeof 0 // “number”

typeof {}// “object”typeof []// “object”typeof null// “object”


typeof returns run-time “tags”

Tags are very coarse-grained types

“undefined”

  • “boolean”

  • “string”

  • “number”

  • “object”

  • “function”


Refinement Types

NumOrBool 

{x|p}

Num

Int

Any 

{v|tag(v)=“number”∨tag(v)=“boolean”}

{n|tag(n)=“number”}

{i|tag(i)=“number”integer(i)}

{x|true}

“set of values x s.t. formula p is true”


Refinement Types

NumOrBool 

Num

Int

Any 

{v|tag(v)=“number”∨tag(v)=“boolean”}

{n|tag(n)=“number”}

{i|tag(i)=“number”integer(i)}

{x|true}

  • Syntactic Sugarfor Common Types


Refinement Types

3::

{n|n=3}

3::

{n|n>0}

3::

{n|tag(n)=“number”integer(n)}

3::

{n|tag(n)=“number”}


Refinement Types

  • Subtyping is Implication

<:

{n|n=3}

<:

{n|n>0}

<:

{n|tag(n)=“number”integer(n)}

<:

{n|tag(n)=“number”}


Refinement Types

  • Subtyping is Implication

{n|n=3}

{n|n>0}

{n|tag(n)=“number”integer(n)}

{n|tag(n)=“number”}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

!true

// false

true

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

0 - 2

// -2

2

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • WAT?!

0 - []

// 0

[]

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • Use types to prevent implicit coercion

(-) :: (Num,Num)Num


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:Any)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • Function type annotation inside comments


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:Any)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

x is boolean...

so negationis well-typed

  • DJS is Path Sensitive


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:Any)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

x is arbitrarynon-boolean value…

so DJS signals error!

  • DJS is Path Sensitive


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:NumOrBool)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:NumOrBool)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • this time,x is a number…

so subtractionis well-typed


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:NumOrBool)Any

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • but returntype is imprecise


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

//: negate :: (x:NumOrBool)NumOrBool

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

/*: negate :: (x:NumOrBool){v|tag(v)=tag(x)} */

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • output type depends on input value


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

/*: negate :: (x:NumOrBool){v|tag(v)=tag(x)} */

Programmer choosesdegree of precisionin specification


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

What is “Duck Typing”?

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

What is “Duck Typing”?

(+) :: (Num,Num)Num

(+) :: (Str,Str)Str

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

What is “Duck Typing”?

  • Can dynamically testthe presence of a methodbut not its type

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

{d|tag(d)=“Dict”∧

{v|has(d,“quack”) 

{v|sel(d,“quack”)::UnitStr}

  • Operators from McCarthy theory of arrays

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

{d|tag(d)=“Dict”∧

{v|has(d,“quack”) 

{v|sel(d,“quack”)::UnitStr}

  • Call produces Str, so concat well-typed

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • DJS is FlowSensitive

x1:{d|d=upd(x0,“f”,7)}

x0:Empty

var x = {};

x.f = 7;

x.f + 2;

  • McCarthy operator

  • DJS verifies that x.f is definitely a number


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • DJS is FlowSensitive

x1:{d|d=upd(x0,“f”,7)}

x0:Empty

var x = {};

x.f = 7;

x.f + 2;

Strong updates to singleton objects

Weak updates to collections of objects


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Typical“Dynamic”

  • Features


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Typical“Dynamic”

  • Features

  • JavaScript

  • tl;dr

  • Harder, butDJS handles them


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

child

  • Upon construction, each object links to a prototype object

parent

grandpa

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Semantics of Key Lookup

var k = “first”; child[k];

child

If child contains k, then

Read k from child

Else if parent contains k, then

Read k from parent

Else if grandpa contains k, then

Read k from grandpa

Else if …

Else

Return undefined

parent

grandpa

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Semantics of Key Lookup

var k = “first”; child[k];

child

If child contains k, then

Read k from child

Else if parent contains k, then

Read k from parent

Else if grandpa contains k, then

Read k from grandpa

Else if …

Else

Return undefined

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

parent

grandpa

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Semantics of Key Lookup

var k = “first”; child[k];

child

If child contains k, then

Read k from child

Else if parent contains k, then

Read k from parent

Else if grandpa contains k, then

Read k from grandpa

Else if …

Else

Return undefined

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

{v|else ifhas(parent,k) then

{v|ifv=sel(parent,k)

parent

grandpa

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Semantics of Key Lookup

var k = “first”; child[k];

child

If child contains k, then

Read k from child

Else if parent contains k, then

Read k from parent

Else if grandpa contains k, then

Read k from grandpa

Else if …

Else

Return undefined

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

{v|else ifhas(parent,k) then

{v|ifv=sel(parent,k)

parent

grandpa

???

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Semantics of Key Lookup

var k = “first”; child[k];

child

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

{v|else ifhas(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k))}

parent

grandpa

???

  • Abstract predicateto summarize theunknown portionof the prototype chain

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

var k = “first”; child[k];

child

{ “first” : “John” }

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

{v|else ifhas(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k))}

parent

grandpa

{ “first” : “Ida”, “last” : “McCarthy” }

???

<:

{v|v=“John”}

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

var k = “last”; child[k];

child

{ “first” : “John” }

{v|ifhas(child,k) then

{v|ifv=sel(child,k)

{v|else ifhas(parent,k) then

{v|ifv=sel(parent,k)

{v|else

{v|ifv=HeapSel(H,grandpa,k))}

parent

grandpa

{ “first” : “Ida”, “last” : “McCarthy” }

???

<:

{v|v=“McCarthy”}

H(Rest of Heap)

...

null


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • Prototype Chain Unrolling

  • Key Idea:

  • Reduce prototypesemantics to decidable theory of arrays


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

  • A finite tuple…

varnums=[0,1,2]

while (…){

nums[nums.length] = 17

}

  • … extended to unbounded collection


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnums=[0,1,2]

while (…){

nums[nums.length] = 17

}

delete nums[1]

for(i=0; i<nums.length; i++)

sum += nums[i]

  • A “hole” in the array

  • Missing element within “length”


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

Track types, “packedness,” and lengthof arrays where possible

{a|a::Arr(T)

{a|packed(a)

{a|len(a)=10}

  • T?

  • -1

  • 0

  • T?

  • 1

  • T?

  • 2

  • T?

  • T?

  • len(a)

  • T?

T?{x|T(x)x=undefined}

X{x|x=undefined}

  • X

  • T

  • T

  • T

  • T

  • X


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

Encode tuplesas arrays

vartup= [17, “cacti”]

{a|a::Arr(Any)

{a|packed(a)len(a)=2

{a|Int(sel(a,0))

{a|Str(sel(a,1))}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

vartup= [17, “cacti”]

tup[tup.length] = true

{a|a::Arr(Any)

{a|packed(a)len(a)=3

{a|…}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

DJS handlesotherquirks:

  • Speciallength property

  • Array.prototype

  • Non-integer keys


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays


What About eval?

Old Types

eval(“…”);

  • Arbitrary code loading


What About eval?

Old Types

New Types

eval(“…”);

//: #assume

New Types

  • “Contract Checking” at Run-timeaka “Gradual Typing”


Recap of DJS Techniques

  • Logic!

  • Path and Flow Sensitivity

  • Prototype Unrolling

  • Syntactic Sugar


Outline

  • Motivation

  • Our Approach: Logic!

  • Evaluation


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests

  • Four inheritance patterns fromCrockford’s JS: The Good Parts


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests

  • Array-manipulating examplesfrom SunSpider


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests

  • typeOf() function to replace typeoffrom Closure Compiler


13 Benchmarks

arrays

“The Good Parts”

prototypes

objects

lambdas

type-tests

  • Well-typed programsdon’t have run-time errors


Implementation

DJSProgram

DesugarerBased on Guha et al.[ECOOP 2010]

JavaScript  λ-Calculus + References + Prototypes

Desugared

Program


Implementation

DJSProgram

  • Programmer Chooses Warnings or Errors

  • Local Type Inference

  • Subtyping w/o Z3 If Possible

DesugarerBased on Guha et al.[ECOOP 2010]

Z3 SMTSolver

Type

Checker

Desugared

Program


Annotation Burden

(Improved since paper)

  • += ~300 LOC to start

  • += ~100 LOC annotations

  • =+ ~400 LOC total

  • 33% Annotation Overhead

  • Common Cases Simplified via

  • Syntactic Sugar and Local Type Inference


Performance

(Improved since paper)

  • Total benchmark suite:

  • ~10 seconds

  • ~1100 Z3 queries

  • 11/13 benchmarks in 0-1 s

  • Common Cases Fast via

  • Syntactic Reasoning When Possible


Future Work

Syntax, Inference, Performance

Larger Examples

Type Checker in JS; Run in Browser

IDE Support for Refactoring, etc.


JavaScript

“The Good Parts”

DJS

Types via Logic!


Thanks!

D

::

ravichugh.com/djs

PS: I’m on the Job Market


Extra Slides


  • DependentJavaScript[this paper]

  • System D[POPL ’12]

“Usability”

refinement types

F≤

∨, ∧

+ nested refinements

DJS

occurrence types

Coq

dependent types

syntactic types

JS

Expressivity


System D [POPL 2012]

+ Types for JS Primitives

+ Strong Updates

+ Quirky JS Arrays

+ Prototype Inheritance

Dependent JavaScript (DJS)


{p}{v|p}

Function Types and Objects

/*: x:NumOrBool {iteNum(x) Num(v) Bool(v)} */

function negate(x) {

x=(typeofx==“number”)? 0 – x : !x

returnx

}

/*: x:Any{vifffalsy(x)} */

function negate(x) {

x=(typeofx==“number”)? 0 – x : !x

returnx

}


Function Types and Objects

  • x:T1/H1T2/H2

input type

output heap

input heap

output type

ObjHas(d,k,H,d’)has(d,k)HeapHas(H,d’,k)

/*: x:Ref / [x |-> d:Dict |> x.pro]

{viffObjHas(d,”f”,curHeap,x.pro)} / sameHeap */

function hasF(x) {

return“f”in x

}


Function Types and Objects

  • x:T1/H1T2/H2

input type

output heap

input heap

output type

ObjSel(d,k,H,d’)

itehas(d,k) sel(d,k) HeapSel(H,d’,k)

/*: x:Ref / [x |-> d:Dict |> x.pro]

{v=ObjSel(d,”f”,curHeap,x.pro)} / sameHeap */

function readF(x) {

returnx.f

}


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • Whoa, but perhaps okay…

0 - “2”

// -2

“2”

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

0 - undefined

// NaN

  • Error would be nicer, but okay…

undefined

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • Seems about right…

0 - {}

// NaN

{}

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

negate has good intentions

But too many corner cases in JS semantics!

varnegate = function(x) {

if (typeofx==“boolean”)

return !x;

else

return0 - x;

}

  • WAT?!

0 - []

// 0

[]

negate()


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

{d|tag(d)=“Dict”∧

{v|has(d,“quack”) 

{v|sel(d,“quack”)::Unit Str}

  • Function types nested inside refinements[POPL 2012]

if (duck.quack)

return“Duck says ” + duck.quack();

else

return“This duck can’t quack!”;


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

var x = {};

x.f;

x.f.f;

  • Programmer configures DJS to report either warnings or errors for:

  • 1)Possible unbound keys


  • Tag-Tests

  • Duck Typing

  • Mutable Objects

  • Prototypes

  • Arrays

var x = {};

x.f;

x.f.f;

  • Programmer configures DJS to report either warnings or errors for:

  • 1)Possible unbound keys

  • 2) Possible run-time errors


  • Login