Upload
others
View
10
Download
0
Embed Size (px)
Citation preview
Type Inference of Asynchronous Arrows in JavaScript
Eric Fritz Tian Zhao
University of Wisconsin - Milwaukee
1 / 22
– 0 –Outline
JS Asynchronicity
Promises
Asynchronous Arrows
Type Inference Strategy
2 / 22
– 0 –Outline
JS Asynchronicity
Promises
Asynchronous Arrows
Type Inference Strategy
2 / 22
– 0 –Outline
JS Asynchronicity
Promises
Asynchronous Arrows
Type Inference Strategy
2 / 22
– 0 –Outline
JS Asynchronicity
Promises
Asynchronous Arrows
Type Inference Strategy
2 / 22
– 1 –JS Asynchronicity
3 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1
handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4
after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1
handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4
after 3
after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1
handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3
after 2
after 1after 0
c
1
after 3
after 2after 1after 0
c
2
handler1
handler2
handler1
handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2
after 1
after 0
c
1
after 3
after 2
after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1
after 0
c
1
after 3after 2
after 1
after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1
after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1
after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1
after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
javascript event loop
stack
queue
main
click #foo
after 4after 3after 2after 1after 0
c
1
after 3after 2after 1after 0
c
2
handler1 handler2
handler1handler2
c
1
c
2
function handler1(ev) {setTimeout (() => $(this).css('color ', '#f00'), 4000);
}
function handler2(ev) {setTimeout (() => $(this).css('color ', '#00f'), 3000);
}
$('#foo').one('click ', handler1 );$('#foo').one('click ', handler2 );
4 / 22
– 2 –Promises - A Solution
Promises/A and A+ (2009)
kriskowal/q (2010) & jQuery Deferred (2011)
ECMAScript 6 Native Promises (2015)
5 / 22
– 2 –Promises - A Solution
Promises/A and A+ (2009)
kriskowal/q (2010) & jQuery Deferred (2011)
ECMAScript 6 Native Promises (2015)
5 / 22
Promise (File Parsing)
readFile('config.json', function(err , text) {if (err) {
// Handle Read Error} else {
try {// Process
} catch (err) {// Handle Parse Error
}}
});
readFile('config.json').catch(err => /* Handle Read Error */).then(text => /* Process */).catch(err => /* Handle Parse Error */);
6 / 22
– 3 –Asynchronous Arrows
Generalizing Monads to Arrows (Hughes 2000)
Arrowlets (Khoo 2009)
7 / 22
– 3 –Asynchronous Arrows
Generalizing Monads to Arrows (Hughes 2000)
Arrowlets (Khoo 2009)
7 / 22
arrows
c
a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c
a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c
a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c
a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
arrows
c a
b
Go!
p
yield
async point
progress event
b
progress event
Elem Event
1 let a = new EventArrow('click ');2 let b = ...3 let x = a.seq(b);4
5 let c = new ElemArrow('#enter ');6 let y = c.seq(x);7 let p = y.run ();8 ...9 p.cancel ();
8 / 22
all combinator (parallel, unordered load)
ajax
2
done
ajax
1
ajax
3
let done = function(data1 , data2 , data3) { ... }let ajax1 = new AjaxArrow (() => { url: '/item/1');let ajax2 = new AjaxArrow (() => { url: '/item/2');let ajax3 = new AjaxArrow (() => { url: '/item/3');
let loadAll = Arrow.all(ajax1 , ajax2 , ajax3 ).seq(done.lift ());
9 / 22
repeat combinator (chunked array processing)
process
update
v
v
0 hloop : v 0iv
0v
00hhalt : v 00i
function processChunk(array , start) {for (let i = start; i < start + 100 && i < array.length; i++) {
processElem(array[i]);}
return start >= array.length? Arrow.halt() // base case: Arrow.loop([array , start + 100]); // enable feedback
}
let processArray = processChunk.lift ().tap(update ). repeat ();
10 / 22
repeat combinator (chunked array processing)
process
update
v
v
0 hloop : v 0i
v
0v
00hhalt : v 00i
function processChunk(array , start) {for (let i = start; i < start + 100 && i < array.length; i++) {
processElem(array[i]);}
return start >= array.length? Arrow.halt() // base case: Arrow.loop([array , start + 100]); // enable feedback
}
let processArray = processChunk.lift ().tap(update ). repeat ();
10 / 22
repeat combinator (chunked array processing)
process
update
v
v
0 hloop : v 0i
v
0v
00hhalt : v 00i
function processChunk(array , start) {for (let i = start; i < start + 100 && i < array.length; i++) {
processElem(array[i]);}
return start >= array.length? Arrow.halt() // base case: Arrow.loop([array , start + 100]); // enable feedback
}
let processArray = processChunk.lift ().tap(update ). repeat ();
10 / 22
any combinator (asynchronous timeout)
↵
ajax
process
delay
timeout
�
let process = ...let timeout = ...
let fetch = Arrow.any(new AjaxArrow (() => { url: '/items ' }). seq(process),new DelayArrow (30*1000). seq(timeout),
);
11 / 22
any combinator (asynchronous timeout)
↵
ajax
process
delay
timeout
�
let process = ...let timeout = ...
let fetch = Arrow.any(new AjaxArrow (() => { url: '/items ' }). seq(process),new DelayArrow (30*1000). seq(timeout),
);
11 / 22
any combinator (asynchronous timeout)
↵
ajax
process
delay
timeout
�
let process = ...let timeout = ...
let fetch = Arrow.any(new AjaxArrow (() => { url: '/items ' }). seq(process),new DelayArrow (30*1000). seq(timeout),
);
11 / 22
noemit combinator (complex asynchronous timeout)
win
delay
loss
�
1 let win = ...2 let loss = ...3 let play = ...4 play = noemit(play);5
6 let timedGame = Arrow.any(7 play.seq(win),8 new DelayArrow (30*1000). seq(loss),9 );
12 / 22
noemit combinator (complex asynchronous timeout)
win
delay
loss
�
1 let win = ...2 let loss = ...3 let play = ...4 play = noemit(play);5
6 let timedGame = Arrow.any(7 play.seq(win),8 new DelayArrow (30*1000). seq(loss),9 );
12 / 22
noemit combinator (complex asynchronous timeout)
win
delay
loss
�
1 let win = ...2 let loss = ...3 let play = ...4 play = noemit(play);5
6 let timedGame = Arrow.any(7 play.seq(win),8 new DelayArrow (30*1000). seq(loss),9 );
12 / 22
noemit combinator (complex asynchronous timeout)
win
delay
loss
�
1 let win = ...2 let loss = ...3 let play = ...4 play = noemit(play);5
6 let timedGame = Arrow.any(7 play.seq(win),8 new DelayArrow (30*1000). seq(loss),9 );
12 / 22
try (ajax failure)
ajax
process
failure
String
�
uncaught error
let process = ...let failure = ...
let fetch = Arrow.try(new AjaxArrow(url => { 'url': url })process ,failure ,
);
13 / 22
try (ajax failure)
ajax
process
failure
String
�
uncaught error
let process = ...let failure = ...
let fetch = Arrow.try(new AjaxArrow(url => { 'url': url })process ,failure ,
);
13 / 22
try (ajax failure)
ajax
process
failure
String
�
uncaught error
let process = ...let failure = ...
let fetch = Arrow.try(new AjaxArrow(url => { 'url': url })process ,failure ,
);
13 / 22
try (ajax failure)
ajax
process
failure
String
�
uncaught error
let process = ...let failure = ...
let fetch = Arrow.try(new AjaxArrow(url => { 'url': url })process ,failure ,
);
13 / 22
– 4 –Type Inference Strategy
14 / 22
Memory (Sample Application)
var selectOne = select.lift().on('click ').whileTrue ();
var round = Arrow.id().tap(clear).seq(selectOne).seq(selectOne).seq(validate.lift ()).carry ().wait (500).tap(freeze).wait (500);
var game = Arrow.id().tap(round).seq(cardsLeft.lift ()).whileTrue ();
var play = initialize.lift().wait (1000).seq(game).seq(won.lift ());
15 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem
Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem
Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem
Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem
Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .. . .
. . .
Cannot read property ‘on’ of null
Elem Elem
()
16 / 22
Memory (Topology)
Event
s
r
. . .. . .
c
. . .
. . .
. . .
Cannot read property ‘on’ of null
Elem Elem
()
16 / 22
arrow type
⇠⌧ ::= ⌧
in
; ⌧out
\ ( C , E )
Set of subtype constraints ⌧ ⌧
Set of possible exceptions types
Examples
IElem ; (Event,Bool)
I ↵ ; � \ ({↵ �}, ;)I
String ; [Number ] \ (;, {AjaxError ,ValidationError})
17 / 22
arrow type
⇠⌧ ::= ⌧
in
; ⌧out
\ ( C , E )
Set of subtype constraints ⌧ ⌧
Set of possible exceptions types
ExamplesI
Elem ; (Event,Bool)
I ↵ ; � \ ({↵ �}, ;)I
String ; [Number ] \ (;, {AjaxError ,ValidationError})
17 / 22
combinator type (constraint example)
a
i
: ⌧i
; ⌧ 0i
\ (Ci
, E
i
), C
0i
= {↵ ⌧i
, ⌧ 0i
�}
any(a1
, . . . , an
) : ↵ ; � \ ([
C
0i
[[
C
i
,[
E
i
)
All arrows receive the same input
Any arrow may produce the combinator’s result
Any arrow may still throw exception from any arrow
18 / 22
combinator type (exceptions example)
a
i
: ⌧i
; ⌧ 0i
\ (Ci
, E
i
)
C
0 = {⌧ 01
⌧2
, ⌧ 02
�, ⌧ 03
�} [ { ⌧ ⌧3
| ⌧ 2 E
1
}
try(a1
, a2
, a3
) : ⌧1
; � \ (C 0 [[
C
i
, E
2
[ E
3
)
Exception handler might be called
Exceptions cannot leak from a
1
Exception handler must accept all errors produced by a
1
19 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)
(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)
(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Type Inference
Event
s
� ; �
Elem ; Event
↵ ; (↵,↵)
(Elem,Event) ; Bool
(�,Elem) ; (�,Event)
↵ ; (�,Event) \ ({↵ �,↵ Elem}, ;)
Elem ; Bool
20 / 22
Common Questions
Developer BurdenI Annotations are relatively infrequent
Performance OverheadI Tolerable in practice (types are minimized)I Type inference is pluggable - can (and should) be disabled
Why Not Promises?I No time to type-check Promises
21 / 22
Common Questions
Developer BurdenI Annotations are relatively infrequent
Performance OverheadI Tolerable in practice (types are minimized)I Type inference is pluggable - can (and should) be disabled
Why Not Promises?I No time to type-check Promises
21 / 22
Common Questions
Developer BurdenI Annotations are relatively infrequent
Performance OverheadI Tolerable in practice (types are minimized)I Type inference is pluggable - can (and should) be disabled
Why Not Promises?I No time to type-check Promises
21 / 22
– Thank You –
22 / 22