Keigo Imai1
(with Rumyana Neykova2, Nobuko Yoshida3 and Shoji Yuen4)
1Gifu University (JP) 2Brunel University London (UK)
3Imperial College London (UK) 4Nagoya University (JP)
PLAS Group Seminar, University of Kent
16th Sept. 2019
1
Global Protocol Combinators:
Static Structural Multiparty Sessions Over
Simply Typed Channels
in OCaml
2
(A supplemental slide at VeTSS 2019 workshop lightning talk)
Deadlocks in message-passing concurrency: Protocols prevent them!
3
A
B C
A ring-form
multiparty
communication:
Concurrent
programming is difficult!
Deadlocks in message-passing concurrency: Protocols prevent them!
4
A
B C
A ring-form
multiparty
communication:
Concurrent
programming is difficult!
C
wrong usage (direction)…
② input① output
order matters…
Deadlocks in message-passing concurrency: Protocols prevent them!
5
A
B C
A ring-form
multiparty
communication:
Concurrent
programming is difficult!
A B C
Communication protocol!
C
wrong usage (direction)…
② input① output
order matters…
Deadlocks in message-passing concurrency: Protocols prevent them!
6
A
B C
A ring-form
multiparty
communication:
Concurrent
programming is difficult!
A B C
Communication protocol!
C
wrong usage (direction)…
② input① output
order matters…
Best practice:
1. Design a communication protocol and check it
2. Focus on its local behaviours
3. Enforce protocol in the program code
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
7
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
[Honda et al., 2008]
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
8
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
"well-formed": protocol G iswf(G) ✔
G = C → S. S → C.end
deadlock-free
[Honda et al., 2008]
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
9
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
"well-formed": protocol G iswf(G) ✔
G = C → S. S → C.end
deadlock-free
G↾C = LC = LSG↾S
S! S?
C? C!
LC =
LS =
: "views" of the protocol
[Honda et al., 2008]
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
10
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢
"well-formed": protocol G iswf(G) ✔
G = C → S. S → C.end
deadlock-free
G↾C = LC = LSG↾S
S! S?
C? C!
LC =
LS =
: "views" of the protocol
[Honda et al., 2008]
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
11
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢
"well-formed": protocol G iswf(G) ✔
G = C → S. S → C.end
deadlock-free
G↾C = LC = LSG↾S
S! S?
C? C!
LC =
LS =
: "views" of the protocol
deadlock-free!
[Honda et al., 2008]
deadlock-free?
Multiparty Session Types (MPSTs): Protocol-based deadlock freedom
12
C S
a "ping" protocol
③ Give concurrent processes (programs) and check their types
① Write a Global Type and check it
② Derive Local Types by End Point Projection (↾)
PC | PS
The system PC | PS is
✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢
"well-formed": protocol G iswf(G) ✔
G = C → S. S → C.end
deadlock-free
G↾C = LC = LSG↾S
S! S?
C? C!
LC =
LS =
: "views" of the protocol
deadlock-free!
[Honda et al., 2008]
How to implement MPSTs
in a programming language?
Question
③ LC ⊢ PC ?
Go
Thread
State of the art: Deadlock freedom via code generation
13
① wf(G) ?
② G↾C
Global
Protocol File
Go
Thread
Go
Thread
In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
③ LC ⊢ PC ?
Go
Thread
State of the art: Deadlock freedom via code generation
14
① wf(G) ?
② G↾C
Global
Protocol File
Go
Thread
Go
Thread
In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
deadlock-free
(Well-formedness checking
and End Point Projection)
Go type
(Generated
code)
Go type
(Generated
code)
Go type
(Generated
code)
Code
generation
✔
③ LC ⊢ PC ?
Type checking
by
Go compiler
✔ (type checking to check
protocol conformance)
Go
Thread
State of the art: Deadlock freedom via code generation
15
① wf(G) ?
② G↾C
Global
Protocol File
Go
Thread
Go
Thread
In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
deadlock-free
(Well-formedness checking
and End Point Projection)
Go type
(Generated
code)
Go type
(Generated
code)
Go type
(Generated
code)
Code
generation
✔
③ LC ⊢ PC ?
Type checking
by
Go compiler
✔ (type checking to check
protocol conformance)
Go
Thread
State of the art: Deadlock freedom via code generation
16
① wf(G) ?
② G↾C
Global
Protocol File
Go
Thread
Go
Thread
In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
deadlock-free
(Well-formedness checking
and End Point Projection)
Go type
(Generated
code)
Go type
(Generated
code)
Go type
(Generated
code)
Code
generation
✔
deadlock-free
③ LC ⊢ PC ?
Type checking
by
Go compiler
✔ (type checking to check
protocol conformance)
Go
Thread
State of the art: Deadlock freedom via code generation
17
① wf(G) ?
② G↾C
Global
Protocol File
Go
Thread
Go
Thread
In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
deadlock-free
(Well-formedness checking
and End Point Projection)
Go type
(Generated
code)
Go type
(Generated
code)
Go type
(Generated
code)
Code
generation
✔
deadlock-free
Is it possible to implement MPSTs
without code generation?
Question
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
18
Yes (!) How?
↓ A single OCaml program code file (.ml)
OCaml
Thread
OCaml
Thread
OCaml
Thread
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
19
Yes (!) How?
↓ A single OCaml program code file (.ml)
OCaml
Thread
OCaml
Thread
OCaml
Thread
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
20
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking &
inference
Yes (!) How?
↓ A single OCaml program code file (.ml)
OCaml
Thread
OCaml
Thread
OCaml
Thread
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
21
Type checking
by
OCaml compiler
✔
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking &
inference
Yes (!) How?
↓ A single OCaml program code file (.ml)
OCaml
Thread
OCaml
Thread
OCaml
Thread
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
22
Type checking
by
OCaml compiler
✔
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking &
inference
Yes (!)
deadlock-free!
How?
↓ A single OCaml program code file (.ml)
OCaml
Thread
OCaml
Thread
OCaml
Thread
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom solely by Types!
23
Type checking
by
OCaml compiler
✔
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking &
inference
Yes (!)
deadlock-free!
How?
How/why do they work??
Global Combinators and well-formedness check
24
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
Global Combinators and well-formedness check
25
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
Global Combinators and well-formedness check
26
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
Global Combinators and well-formedness check
27
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))
choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2
Example: Adding a branch to Simple OAuth protocol
(a few plumbings needed to convince the type checker)
Each branch must begin from s
Global Combinators and well-formedness check
28
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))
choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2
NB: Branching in a protocol is a source of concurrency issues
(a few plumbings needed to convince the type checker)
Global Combinators and well-formedness check
29
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))
choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2
NB: Branching in a protocol is a source of concurrency issues
(a few plumbings needed to convince the type checker)
Non-determinism/
Deadlock
in a protocol
a
Global Combinators and well-formedness check
30
① wf(G) ✔
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
(r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads)
Example: Simple OAuth protocol
s c a
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))
choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2
NB: Branching in a protocol is a source of concurrency issues
(a few plumbings needed to convince the type checker)
… is reported as a type error
Non-determinism/
Deadlock
in a protocol
a
(Deadlock and type errors: An analysis)
31
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))a
poke a instead of c
The MPST theory rejects it: they are not "mergeable".
Forming a "mixed choice" (which causes nondeterminism)
c's first action is input from s
c's first action is output to a
Deriving local types via type inference
OCaml infers Local Types from global combinators.
32
② G↾C
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
Example (again): Simple OAuth protocol
s c a
All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
Deriving local types via type inference
OCaml infers Local Types from global combinators.
33
② G↾C
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
Example (again): Simple OAuth protocol
s c a
All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
val oauth :
[ `cons of
< role_C : < login : ('a * close) out lin > > *
[ `cons of
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin > *
[ `cons of
< role_C : [> `password of 'b *
< role_C : < auth : ('c *
close) out lin > > ] inp lin > *
([ `cons of close * 'x ] as 'x) ] ] ] Seq.t
c!login
s?login a!pass a?auth
s!pass s?auth
s
c
a
Deriving local types via type inference
OCaml infers Local Types from global combinators.
34
② G↾C
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
Example (again): Simple OAuth protocol
s c a
All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
val oauth :
[ `cons of
< role_C : < login : ('a * close) out lin > > *
[ `cons of
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin > *
[ `cons of
< role_C : [> `password of 'b *
< role_C : < auth : ('c *
close) out lin > > ] inp lin > *
([ `cons of close * 'x ] as 'x) ] ] ] Seq.t
c!login
s?login a!pass a?auth
s!pass s?auth
s
c
a
Destination role's names are a method of an object
< role_S
< role_A
< role_A
Deriving local types via type inference
OCaml infers Local Types from global combinators.
35
② G↾C
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
Example (again): Simple OAuth protocol
s c a
All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
val oauth :
[ `cons of
< role_C : < login : ('a * close) out lin > > *
[ `cons of
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin > *
[ `cons of
< role_C : [> `password of 'b *
< role_C : < auth : ('c *
close) out lin > > ] inp lin > *
([ `cons of close * 'x ] as 'x) ] ] ] Seq.t
c!login
s?login a!pass a?auth
s!pass s?auth
s
c
a
Output labels are methods in an object
< password
Destination role's names are a method of an object
< role_S
< role_A
< role_A
Deriving local types via type inference
OCaml infers Local Types from global combinators.
36
② G↾C
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
Example (again): Simple OAuth protocol
s c a
All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
val oauth :
[ `cons of
< role_C : < login : ('a * close) out lin > > *
[ `cons of
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin > *
[ `cons of
< role_C : [> `password of 'b *
< role_C : < auth : ('c *
close) out lin > > ] inp lin > *
([ `cons of close * 'x ] as 'x) ] ] ] Seq.t
c!login
s?login a!pass a?auth
s!pass s?auth
s
c
a
Input labels are (polymorphic) variant type tags
[ `login
[ `auth
Output labels are methods in an object
< password
Destination role's names are a method of an object
< role_S
< role_A
< role_A
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
37
③ LC ⊢ PC ✔
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
38
< role_S
Select destination role via method invocation (#)
role_S
③ LC ⊢ PC ✔
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
39
< role_S
Select destination role via method invocation (#)
role_S
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
40
< role_S
Select destination role via method invocation (#)
role_S
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
"Next" channel is supplied as a part of the returned value
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
41
< role_S
Select destination role via method invocation (#)
role_S
< role_A
role_A
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
"Next" channel is supplied as a part of the returned value
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
42
< role_S
Select destination role via method invocation (#)
role_S
< role_A
role_A
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
"Next" channel is supplied as a part of the returned value
< password
#password
Select an output label via method invocation (#), then
send it with a payload
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
43
< role_S
Select destination role via method invocation (#)
role_S
< role_A
role_A
role_A
< role_A
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
"Next" channel is supplied as a part of the returned value
< password
#password
Select an output label via method invocation (#), then
send it with a payload
let ch = get_ch c oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
Protocol conformance via OCaml's type checking
44
< role_S
Select destination role via method invocation (#)
role_S
< role_A
role_A
`auth
[ `auth
role_A
< role_A
③ LC ⊢ PC ✔
[ `login
`login
… and receive on it, then pattern-match the value against variant tags (labels)
received payload
"Next" channel is supplied as a part of the returned value
< password
#password
Select an output label via method invocation (#), then
send it with a payload
let ch = get_ch s oauth (* get a MPST channel for s *)
val ch :
< role_S : [> `login of 'a *
< role_A : < password : ('b *
< role_A : [> `auth of 'c *
close ] inp lin >) out lin > > ] inp lin >
OCaml>
let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish))
let thread_C () =
match receive ch#role_S with
| `login((u:string), ch)->
let ch = send ch#role_A#password "asdf" in
match receive ch#role_A with
| `auth((b:bool), ch) ->
close ch
45
Protocol conformance via OCaml's type checking③ LC ⊢ PC ✔
ro
If there is a
typo …
OCaml reports a type error at this point
↓ A single OCaml Source code file (.ml)
OCaml
Program
OCaml
Program
OCaml
Program
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom by Types!
46
Type checking
by
OCaml compiler
✔
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking
& inference
Recap
deadlock-free!
↓ A single OCaml Source code file (.ml)
OCaml
Program
OCaml
Program
OCaml
Program
Protocol
in OCaml
③ LC ⊢ PC ?
① wf(G) ?
② G↾C
Global Protocol Combinator : Deadlock freedom by Types!
47
Type checking
by
OCaml compiler
✔
✔
deadlock-free
OCaml types OCaml types OCaml types
Type
checking
& inference
Recap
deadlock-free!
Are they really correct??
GPC: Are they correct
48
A. Key idea: Global Combinators pre-generate channels
❖ Multiparty channels as nested sequence of simply-typed channels
B. Formalisation of GPC with Deadlock-freedom Theorem
❖ OCamlM: A minimal concurrent language
❖ Typing rules for Global Combinators
C. Implementation: GPC as a typed DSL in OCaml
❖ Based on a set of type manipulation techniques
(GADTs, field label encoding, and plumbings such as polymorphic record extension)
GPC key ingredients
GPC: Are they correct
49
A. Key idea: Global Combinators pre-generate channels
❖ Multiparty channels as nested sequence of simply-typed channels
B. Formalisation of GPC with Deadlock-freedom Theorem
❖ OCamlM: A minimal concurrent language
❖ Typing rules for Global Combinators
C. Implementation: GPC as a typed DSL in OCaml
❖ Based on a set of type manipulation techniques
(GADTs, label encoding, and plumbings such as polymorphic record extension)
GPC key ingredients
50
Let's start cooking!!
A. Key idea: Global Combinators pre-generate channels
A. Key idea: Global Combinators pre-generate channels
51
S
C A
⟨⟩ ⟨⟩
⟨⟩
let oAuth = finish
A. Key idea: Global Combinators pre-generate channels
52
S
C A
Sauth
⟨?Sauth⟩ ⟨!Sauth⟩
⟨⟩
let oAuth = (A → C) auth finish
A. Key idea: Global Combinators pre-generate channels
53
let oAuth = (C → A) password ((A → C) auth finish)
S
C A
Sauth
Spasswd
⟨!Spasswd; ?Sauth⟩ ⟨?Spasswd; !Sauth⟩
⟨⟩
A. Key idea: Global Combinators pre-generate channels
54
let oAuth = (S → C) login ((C → A) password ((A → C) auth finish))
S
C
A
⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩
Sauth
Spasswd
Slogin
⟨!Slogin ⟩
A. Key idea: Global Combinators pre-generate channels
55
let oAuth = (S → C) login ((C → A) password ((A → C) auth finish))
S
C
A
⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩
Sauth
Spasswd
Slogin
⟨!Slogin ⟩
Distribute them and start the communication
56
PS
PC
PA
!Slogin.0| ?Slogin ; !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0
Distribute them and start the communication
57
PS
PC
PA
0| !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0
Distribute them and start the communication
58
PS
PC
PA
0| ?Sauth.0| !Sauth.0
Distribute them and start the communication
59
PS
PC
PA
0| 0| 0
Distribute them and start the communication
60
PS
PC
PA
!Slogin.0| ?Slogin ; !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0
❖ All these channels are simply-typed (hence no type-errors)
❖ Global combinators aim to be deadlock-free
❖ The nested structure enforces usage order
Point
GPC: Are they correct? (cont.)
61
A. Key idea: Global Combinators pre-generate channels
❖ Multiparty channels as nested sequence of simply-typed channels
B. Formalisation of GPC (with Deadlock-freedom Theorem)
❖ OCamlM: A minimal concurrent language
❖ Typing rules for Global Combinators (with hints to OCaml DSL)
❖ Session Type merging
C. Implementation: GPC as a typed DSL in OCaml
❖ Based on a set of type manipulation techniques
(GADTs, field label encoding, and plumbings such as polymorphic record extension)
GPC key ingredients
B. OCamlM: Formalisation of GPC with Deadlock-freedom Theorem
• A minimal concurrent language with structural subtyping,
equi-recursive types and simply-typed channels
• Typing rules for global combinators
62
Typing rules
63
p1 pn
… … …
Point: give an index for each role (and order roles)
wf(G) ✔, G↾C
The typing rule for (-->)
64
p1 pn
…
pi pj
… …
wf(G) ✔, G↾C
i
The typing rule for (-->)
65
p1 pn
…
pi pj
… …
Index-based type update
wf(G) ✔, G↾C
i
The typing rule for (-->)
66
p1 pn
…
pi pj
… …
Index-based type update
p1 pn
…
pi pj
… …
"Wrap" with opponent's role names and labels
wf(G) ✔, G↾C
i
The typing rule for (-->)
67
p1 pn
…
pi pj
… …
Index-based type update
p1 pn
…
pi pj
… …
"Wrap" with opponent's role names and labels
Implement them by using GADTs and
polymorphic lens (explained later)
available in OCaml
wf(G) ✔, G↾C
i
The typing rule for (-->)
68
p1 pn
…
pi pj
… …
Index-based type update
p1 pn
…
pi pj
… …
"Wrap" with opponent's role names and labels
Requires first-class record fields
(methods) and variant tags
⇒ Encode them as values
encode it in OCaml
Implement them by using GADTs and
polymorphic lens (explained later)
available in OCaml
wf(G) ✔, G↾C
i
The typing rule for branching (choice_at)
69
wf(G) ✔, G↾C
The typing rule for branching (choice_at)
70
Ensure that pa is a sending
wf(G) ✔, G↾C
The typing rule for branching (choice_at)
71
Ensure that pa is a sending
Output labels must be disjoint (deterministic)
wf(G) ✔, G↾C
The typing rule for branching (choice_at)
72
Ensure that pa is a sending
Output labels must be disjoint (deterministic)
Merge two records (objects) into one
wf(G) ✔, G↾C
The typing rule for branching (choice_at)
73
Ensure that pa is a sending
Output labels must be disjoint (deterministic)
Merge two records (objects) into one
Encode disjoint record merging
encode it in OCaml
wf(G) ✔, G↾C
The typing rule for branching (choice_at)
74
wf(G) ✔, G↾C
Too restrictive for communication protocols
Solution: Subtyping!
Requires each role having the same type (behaviour) in each branch
→ seems standard wrt. if-then-else construct, but
The typing rule for branching (choice_at)
75
wf(G) ✔, G↾C
Too restrictive for communication protocols
Solution: Subtyping!
Row polymorphism
(objects and polymorphic variants)
available in OCaml
Requires each role having the same type (behaviour) in each branch
→ seems standard wrt. if-then-else construct, but
Typing rules
76
…
p1 pn
…
pi
…
p1 pn
…
pi
…
p1 pn
…
pi
…
Γ ⊢ choice … {g1; g2} : ⋯×p&{m1:T1, m2:T2}×⋯
Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g2 : ⋯×p&{m2:T2}×⋯
Desired type
(According to Full Merging in MPST)
A problem:
p&{m1:T1} ≠ p&{m2:T2}
Typing rules
77
…
p1 pn
…
pi
…
p1 pn
…
pi
…
p1 pn
…
pi
…
Γ ⊢ choice … {m1:g1; m2:g2} : ⋯×p&{m1:T1, m2:T2}×⋯
Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g1 : ⋯×p&{m2:T2}×⋯
? ?
Typing rules
78
…
p1 pn
…
pi
…
p1 pn
…
pi
…
p1 pn
…
pi
…
Γ ⊢ g1 : ⋯×p&{m1:T1, m2:T2}×⋯ Γ ⊢ g2 : ⋯×p&{m1:T1, m2:T2}×⋯
Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g1 : ⋯×p&{m2:T2}×⋯
Γ ⊢ choice … {g1; g2} : ⋯×p&{m1:T1, m2:T2}×⋯
p&{m1:T1} ≤ p&{m1:T1; m2:T2} p&{m2:T2} ≤ p&{m1:T1; m2:T2}
Subtyping!!
Deadlock and type errors: An analysis
79
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))a
poke a instead of c
The MPST theory rejects it: they are not "mergeable".
Forming a "mixed choice" (which causes nondeterminism)
Deadlock and type errors: An analysis
80
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))a
poke a instead of c
The MPST theory rejects it: they are not "mergeable".
Forming a "mixed choice" (which causes nondeterminism)
c's first action is output to a <a: <quit: !bool*cont2>>
Deadlock and type errors: An analysis
81
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))a
poke a instead of c
The MPST theory rejects it: they are not "mergeable".
Forming a "mixed choice" (which causes nondeterminism)
c's first action is input from s <s: ?[login_str*cont1]>
c's first action is output to a <a: <quit: !bool*cont2>>
Deadlock and type errors: An analysis
82
let oauth_branch =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login ((c --> a) password ((a --> c) auth finish)))
(s, (s --> c) cancel ((c --> a) quit finish))a
poke a instead of c
The MPST theory rejects it: they are not "mergeable".
Forming a "mixed choice" (which causes nondeterminism)
c's first action is input from s <s: ?[login_str*cont1]>
c's first action is output to a <a: <quit: !bool*cont2>>
No least upper bound (common supertype)
⇒ type error
No least upper bound (common supertype)
⇒ type error
A note on typing
83
<r: ?[lab: T1*T2]>
<r: <lab: !T1*T2>>
Input and output session types are not symmetric with each other. Why?
sok : ?bool, scancel : ?int
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
Making a multiplexed channel from
simply-typed channels
A note on typing
84
<r: ?[lab: T1*T2]>
<r: <lab: !T1*T2>>
Input and output session types are not symmetric with each other. Why?
sok : ?bool, scancel : ?int
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
Concurrent ML (Reppy, 1993)
Types are slightly modified, they uses "events" in reality
Making a multiplexed channel from
simply-typed channels
A note on typing
85
<r: ?[lab: T1*T2]>
<r: <lab: !T1*T2>>
Input and output session types are not symmetric with each other. Why?
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
Concurrent ML (Reppy, 1993)
Types are slightly modified, they uses "events" in reality
Making a multiplexed channel from
simply-typed channels
A note on typing
86
<r: ?[lab: T1*T2]>
<r: <lab: !T1*T2>>
Input and output session types are not symmetric with each other. Why?
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)
: List[ ?[ok_(boolו), cancel_(intׅ)] ]
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
Concurrent ML (Reppy, 1993)
Types are slightly modified, they uses "events" in reality
Making a multiplexed channel from
simply-typed channels
A note on typing
87
<r: ?[lab: T1*T2]>
<r: <lab: !T1*T2>>
Input and output session types are not symmetric with each other. Why?
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)
: List[ ?[ok_(boolו), cancel_(intׅ)] ]
choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel))
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
Concurrent ML (Reppy, 1993)
Types are slightly modified, they uses "events" in reality
Making a multiplexed channel from
simply-typed channels
GPC: Are they correct? (cont.)
88
A. Key idea: Global Combinators pre-generate channels
❖ Multiparty channels as nested sequence of simply-typed channels
B. Formalisation of GPC (with Deadlock-freedom Theorem)
❖ OCamlM: A minimal concurrent language
❖ Typing rules for Global Combinators (with hints to OCaml DSL)
❖ Session Type merging
C. Implementation: GPC as a typed DSL in OCaml
❖ Based on a set of type manipulation techniques
(GADTs, field label encoding, and details of plumbings for polymorphic record extension)
❖ Benchmarks: Garbage collection matters
❖ Linearity monad
GPC key ingredients
Please ask me over beer!
GPC wrap up
89
Global Protocol Combinator: a DSL for writing global protocols
❖ Key Ingredients: Global Combinators
❖ Covers all basic MPST features (including full merging)
❖ Extensions: HTTP, and OAuth Example (on top of it), and more
OCamlM: fomalisation of a minimal programming language for GPC
❖ Subject Reduction, Operational Correspondence and Deadlock-freedom
❖ Types for global combinators
❖ Merging is a least upper bound in subtyping relation
Sauth
Spasswd
let oauth = (s --> c) login …
p1 pn
… … …
Future Work
90
A → B
B → C
A → B
• Deadlock-freedom proof on full global combinators
❖ Including more expressive ones (e.g. relaxed loop conditions)
❖ Scatter/Gather (broadcast), undirected internal choice, …
• Implementation in other programming languages
❖ TypeScript (structural subtyping from beginning, and will have recursive types as well)
❖ Haskell (automatically construct global combinators via type classes)
Thank you!
Extra slides
91
Loops are easy (for now)
92
let oAuth = (S → C) login ((C → A) password ((A → C) auth finish))
S
C
A
⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩
Sauth
Spasswd
Slogin
⟨?Slogin ⟩
Loops are easy (for now)
93
let oAuth = fix (λx. (S → C) login ((C → A) password ((A → C) auth x))
S
C
A
μx.⟨?Slogin ; !Spasswd; ?Sauth; x ⟩
μx. ⟨?Spasswd; !Sauth; x⟩
Sauth
Spasswd
Slogin
μx. ⟨?Slogin; x⟩
Branchings?
94
S
C
A
Sauth
Spasswd
Slogin
(S → C) login ((C → A) password ((A → C) auth finish))
(S → C) cancel ((C → A) quit finish)
S
C A
Squit
Scancel
+?
Input / output primitives and row-polymorphism in OCaml
95
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
(FP's type inference-friendly structural typing)
Input / output primitives and row-polymorphism in OCaml
96
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Input / output primitives and row-polymorphism in OCaml
97
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Output labels are methods in
an object (fields in a polymorphic record)
Output labels are methods in
an object (fields in a polymorphic record)
Input / output primitives and row-polymorphism in OCaml
98
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
OCaml's row-polymorphism simulates session-type subtyping
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Output labels are methods in
an object (fields in a polymorphic record)
Output labels are methods in
an object (fields in a polymorphic record)
Input / output primitives and row-polymorphism in OCaml
99
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
OCaml's row-polymorphism simulates session-type subtyping
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Output labels are methods in
an object (fields in a polymorphic record)
Output labels are methods in
an object (fields in a polymorphic record)
val ch :
< role_C : [< `password of
string *
< role_C : < auth : (bool * close) out lin; .. >; .. >
] inp lin; .. >
-> unit
Input / output primitives and row-polymorphism in OCaml
100
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
OCaml's row-polymorphism simulates session-type subtyping
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Output labels are methods in
an object (fields in a polymorphic record)
Output labels are methods in
an object (fields in a polymorphic record)
val ch :
< role_C : [< `password of
string *
< role_C : < auth : (bool * close) out lin; .. >; .. >
] inp lin; .. >
-> unit
Inferred polymorphic variant type: it can have less receiving labels
(= in this case it must have password at least since there must be one)
Input / output primitives and row-polymorphism in OCaml
101
let thread_A () =
let `password((p:string), ch) = receive ch#role_C in
let ch = send ch#role_C#auth true in
close ch
OCaml's row-polymorphism simulates session-type subtyping
(FP's type inference-friendly structural typing)
Input labels are
polymorphic variants
Input labels are
polymorphic variants
Output labels are methods in
an object (fields in a polymorphic record)
Output labels are methods in
an object (fields in a polymorphic record)
val ch :
< role_C : [< `password of
string *
< role_C : < auth : (bool * close) out lin; .. >; .. >
] inp lin; .. >
-> unit
Inferred polymorphic variant type: it can have less receiving labels
(= in this case it must have password at least since there must be one)
Inferred object type: it can have more sending labels
Branching
102
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> c) cancel @@ (c --> a) quit finish)
A protocol with branching:
let thread_C () =
match receive ch#role_S with
| `cancel((code:int), ch) -> close (send chc#role_A#quit ())
| `login((), ch) ->
let ch = send ch#role_A#password "asdf" in
let `auth(b, ch) = receive ch#role_A in
close ch
Code for C (waiting for S with an external choice):
Branching
103
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> c) cancel @@ (c --> a) quit finish)
A protocol with branching:
S will decide a branch, then C and A will follow
let thread_C () =
match receive ch#role_S with
| `cancel((code:int), ch) -> close (send chc#role_A#quit ())
| `login((), ch) ->
let ch = send ch#role_A#password "asdf" in
let `auth(b, ch) = receive ch#role_A in
close ch
Code for C (waiting for S with an external choice):
Branching
104
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> c) cancel @@ (c --> a) quit finish)
A protocol with branching:
S will decide a branch, then C and A will follow
let thread_C () =
match receive ch#role_S with
| `cancel((code:int), ch) -> close (send chc#role_A#quit ())
| `login((), ch) ->
let ch = send ch#role_A#password "asdf" in
let `auth(b, ch) = receive ch#role_A in
close ch
Code for C (waiting for S with an external choice):An external choice is a pattern matching
(idiomatic OCaml)
Loops and delegations (1)
105
let oauth2 =
fix (fun self ->
choice_at s (to_c login_cancel_or_retry)
(s, oauth1 ())
(s, (s --> c) retry @@ (c --> a) retry self))
Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default),
programmers can handle recursions very naturally:
Loops and delegations (1)
106
let oauth2 =
fix (fun self ->
choice_at s (to_c login_cancel_or_retry)
(s, oauth1 ())
(s, (s --> c) retry @@ (c --> a) retry self))
recursionrecursion
Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default),
programmers can handle recursions very naturally:
Loops and delegations (1)
107
let oauth2 =
fix (fun self ->
choice_at s (to_c login_cancel_or_retry)
(s, oauth1 ())
(s, (s --> c) retry @@ (c --> a) retry self))
recursionrecursion
protocol reuse
Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default),
programmers can handle recursions very naturally:
Loops and delegations (1)
108
let oauth2 =
fix (fun self ->
choice_at s (to_c login_cancel_or_retry)
(s, oauth1 ())
(s, (s --> c) retry @@ (c --> a) retry self))
recursionrecursion
protocol reuse
val ch_S : < role_C : < cancel : ('_b * close) out lin;
login : ('_c * close) out lin;
retry : ('_d * 'a) out lin > > as 'a
OCaml>
Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default),
programmers can handle recursions very naturally:
Loops and delegations (1)
109
let oauth2 =
fix (fun self ->
choice_at s (to_c login_cancel_or_retry)
(s, oauth1 ())
(s, (s --> c) retry @@ (c --> a) retry self))
recursionrecursion
protocol reuse
val ch_S : < role_C : < cancel : ('_b * close) out lin;
login : ('_c * close) out lin;
retry : ('_d * 'a) out lin > > as 'a
OCaml>
recursionrecursion
Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default),
programmers can handle recursions very naturally:
Loops and delegations (2)
110
let oauth_deleg =
(mst --> wrk) (msg >: get_prot s oauth2)
finish
Delegation doesn't need any special treatment, since OCaml will just infer the delegated type.
However, you can annotate labels with a delegated protocol, like this:
val ch_Mst :
< role_Wrk : < msg :
(< role_C : < cancel : ('_b * close) out lin;
login : ('_c * close) out lin;
retry : ('_d * 'a) out lin > > as 'a *
close) out lin > >
OCaml>
Delegated type
Detecting protocol errors using types
111
Non-determinism/
Deadlock
in a protocol
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> a) cancel @@ (c --> a) quit finish)
NB: Branching is a source of concurrency issues
Detecting protocol errors using types
112
Non-determinism/
Deadlock
in a protocol
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> a) cancel @@ (c --> a) quit finish)
… is also reported as a type error
NB: Branching is a source of concurrency issues
Detecting protocol errors using types
113
Non-determinism/
Deadlock
in a protocol
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> a) cancel @@ (c --> a) quit finish)
… is also reported as a type error
Theorem: if a global type G is well-formed, its encoding
to a global combinator g =⟦G⟧ is well-typed in OCamlM.
NB: Branching is a source of concurrency issues
Detecting protocol errors using types
114
Non-determinism/
Deadlock
in a protocol
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> a) cancel @@ (c --> a) quit finish)
… is also reported as a type error
Theorem: if a global type G is well-formed, its encoding
to a global combinator g =⟦G⟧ is well-typed in OCamlM.
NB: Branching is a source of concurrency issues
Global Combinators have full expressivity of MPST Global Types
[Formalisation] OCamlM : a Minimal calculus for global combinators
Main results:
115
A calculus with structural subtyping, equi-recursive types and
i/o-typed channels
Theorem (Subject Reduction): if ⊢ e and e→* e' then ⊢ e'
Theorem (Operational Correspondence):
(Completeness)
(Soundness)
Corollary (Deadlock Freedom): If an MPST process P is
deadlock-free, OCamlM expression e=⟦P⟧ is deadlock-free.
Other features and Examples
✔ Branchings, loops, delegations
❖ Allows full merging in a branching (next slide)
✔ MPST as a wrapper
❖ Offers global protocol on top of HTTP, DNS, …
❖ Example: OAuth, DNS server, SMTP client, …
❖ Utilise concurrent/distributed libraries: Lwt (lightweight threads) and Unix IPC
✔ More Extensions
❖ Scatter/Gather (broadcast)
❖ Undirected choice (-nolive)
❖ Unbalanced Loops
116
B⊕m1 C⊕m2
B⊕m1C⊕m2
A → B
B → C
A → B
Full merging
117
let oauth1 =
choice_at s (to_c login_or_cancel)
(s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish)
(s, (s --> c) cancel @@ (c --> a) quit finish)
Input labels are
polymorphic variantsA can have different
input branches
Example: A branch happens between S and C.
⇒ Merge A's two behaviours into one
Merging strategy Synopsis Implementations
Plain merging
All branches must have same
labels/continuation (restrictive)
Scalas et al.
(ECOOP 2017)
✔ Full merging
Different input labels/continuations
can be mergeable (more relaxed)
This work
• Benchmarks reflect our design decision to use
mutable long lived objects (e.g channel vectors)
❖ Our work: few mutable long lived objects, created at the start of the protocol
❖ State-of-the-art (linear-decomposition [Scala et.a]): many small channels, created on-demand
(during the protocol execution)
118
Benchmarks
• Comparison with Linear (Binary) Decomposition [Scalas et al., 2017]
❖ Translation from MPST to Linear Types
❖ Continuation Passing Style (CPS):
It creates (and exchanges) a fresh channel at each communication step
❖ Must be slower than us??
• Compete with ours in some cases (!), but CPS is slower in general
❖ OCaml's major GC is doing nice work
• Monad (static linearity checking with overhead) VS. Direct style (dynamic)
119
Put All Slides in right contexts!!
• Most surprising parts:
• (what is it) 簡単に?
programmers can write like this… select opponent role by method, then (a) send by method / (b) receive it and pattern match on variants.
Errors are detected like this… GC well-formedness errors and Local type conformance errors.
Bonus: recursive sessions, session subtyping and delegations are all free.
• (why/how gc-like typing is possible??)
(1) (why EPP is possible, it is operation on types!!: see onion and --> typing.)
(2) (why well-formedness checking is possible? What is well-formedness?: see typing rules)
• (key idea) タマネギ.2枚くらいにおさめる
• (how it is typed) --> typing and implementation (mention that OCaml do not have such first-class?)
• (how deadlock is detected: harder) choice, nondeterminisim and deadlock
choice is like an if-then-else. Two branches are merged into one.
(Sub)typing and global combinator typing prevents occasional wrong branching.
• (how it is imlpemented) lenses and first class record fields
• Choice_at typing and record extensions
❖ Least upper bound is merging
❖ We have more expressive GTs
❖ Subtyping and equi-recursive types
❖ Unguardedness and Unbalanced merging
• Linearity monad
• Deadlock freeness, syntax of local types, and undirected choice (sending and receiving)
• Benchmarks
• Meaning of type errors and relationship to deadlocks
❖ Mergeability and local type syntax
❖ Possibility to extension (i.e. non-directed merging)
❖ Why roles are record fields – what if it was variant tags
120
Channel Vectors: Inhabiting MPSTs as simple channel types
121
TA = B⊕{ok.•; cancel.B&cancel.•} TB = A&{ok.•; cancel.B⊕cancel.•}
Channel Vectors: Inhabiting MPSTs as simple channel types
122
sok scancel1
scancel2
sok scancel1
scancel2
Idea: Put simply-typed channels in a tree-like data structure
TA = B⊕{ok.•; cancel.B&cancel.•} TB = A&{ok.•; cancel.B⊕cancel.•}
Internal Choice is Record
A record having pairs of an output channel and "the rest" in its fields
123
⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s = <B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> >
Pictorially:
Internal Choice is Record
A record having pairs of an output channel and "the rest" in its fields
124
⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s = <B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> >
(scancel, )(sok, )
…
ok cancel
Pictorially:
Internal Choice is Record
A record having pairs of an output channel and "the rest" in its fields
125
⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s =
: ⟨B : ⟨ok: !(int*int)ו; cancel: !(bool) ×⟦…⟧⟩ ⟩
Provided that
• sok : Och, scancel : Och
(! is an output channel type)
<B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> >
(scancel, )(sok, )
…
ok cancel
Pictorially:
External choice is variant input
126
Variant input type: ?[ok_(boolו); cancel_(int× …)]
Variant type: [ok_(boolו); cancel_(int× …)]
("Either ok (with boolו) or cancel (with intׅ)")
("Receives either ok (with boolו) or cancel (with intׅ)")
cancel(_, )ok(_, )
scancel1sok
cancel
external choice
Pictorially: But how?
A Solution from Concurrent ML (Reppy, 1993)
127
… has a set of (event) primitives we need!
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
sok : ?bool, scancel : ?int
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
A Solution from Concurrent ML (Reppy, 1993)
128
… has a set of (event) primitives we need!
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
A Solution from Concurrent ML (Reppy, 1993)
129
… has a set of (event) primitives we need!
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)
: List[ ?[ok_(boolו), cancel_(intׅ)] ]
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
A Solution from Concurrent ML (Reppy, 1993)
130
… has a set of (event) primitives we need!
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)
: List[ ?[ok_(boolו), cancel_(intׅ)] ]
choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel))
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
A Solution from Concurrent ML (Reppy, 1993)
131
… has a set of (event) primitives we need!
choose : List[?T] -> ?T
makes a (multiplexed) channel (external choice)
wrap : (α -> β) -> ?α -> ?β
makes a wrapped channel
sok : ?bool, scancel : ?int
wrap (λx.[ok=(x,•)]) sok
: ?[ok_(boolו)]
wrap (λx.[cancel=(x,…)]) scancel
: ?[cancel_(int×…)]
List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)
: List[ ?[ok_(boolו), cancel_(intׅ)] ]
choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel))
cancel(_, )ok(_, )
scancel1
sok
(scancel2, )
cancel
choose
: ?[ok_(boolו); cancel_(int× …)] (← wanted)
Putting them altogether
132
(scancel, )(sok, )
ok cancel
cancel(_, )ok(_, )
scancel1
sok
(scancel2, )
cancel
choose
B⊕{ok(bool).•; cancel(int).B&cancel(int).•} A&{ok(bool).•; cancel(int).A⊕cancel(int).•}
choice_at A {(A → B) ok finish, (A → B) cancel((B → A) cancel finish)}
cancel(_, )
scancel2
Putting them altogether
133
(scancel, )(sok, )
ok cancel
cancel(_, )ok(_, )
scancel1
sok
(scancel2, )
cancel
choose
B⊕{ok(bool).•; cancel(int).B&cancel(int).•} A&{ok(bool).•; cancel(int).A⊕cancel(int).•}
choice_at A {(A → B) ok finish, (A → B) cancel((B → A) cancel finish)}
cancel(_, )
scancel2

OCaml-MPST / Global Protocol Combinators

  • 1.
    Keigo Imai1 (with RumyanaNeykova2, Nobuko Yoshida3 and Shoji Yuen4) 1Gifu University (JP) 2Brunel University London (UK) 3Imperial College London (UK) 4Nagoya University (JP) PLAS Group Seminar, University of Kent 16th Sept. 2019 1 Global Protocol Combinators: Static Structural Multiparty Sessions Over Simply Typed Channels in OCaml
  • 2.
    2 (A supplemental slideat VeTSS 2019 workshop lightning talk)
  • 3.
    Deadlocks in message-passingconcurrency: Protocols prevent them! 3 A B C A ring-form multiparty communication: Concurrent programming is difficult!
  • 4.
    Deadlocks in message-passingconcurrency: Protocols prevent them! 4 A B C A ring-form multiparty communication: Concurrent programming is difficult! C wrong usage (direction)… ② input① output order matters…
  • 5.
    Deadlocks in message-passingconcurrency: Protocols prevent them! 5 A B C A ring-form multiparty communication: Concurrent programming is difficult! A B C Communication protocol! C wrong usage (direction)… ② input① output order matters…
  • 6.
    Deadlocks in message-passingconcurrency: Protocols prevent them! 6 A B C A ring-form multiparty communication: Concurrent programming is difficult! A B C Communication protocol! C wrong usage (direction)… ② input① output order matters… Best practice: 1. Design a communication protocol and check it 2. Focus on its local behaviours 3. Enforce protocol in the program code
  • 7.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 7 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is [Honda et al., 2008]
  • 8.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 8 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is "well-formed": protocol G iswf(G) ✔ G = C → S. S → C.end deadlock-free [Honda et al., 2008]
  • 9.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 9 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is "well-formed": protocol G iswf(G) ✔ G = C → S. S → C.end deadlock-free G↾C = LC = LSG↾S S! S? C? C! LC = LS = : "views" of the protocol [Honda et al., 2008]
  • 10.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 10 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is ✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢ "well-formed": protocol G iswf(G) ✔ G = C → S. S → C.end deadlock-free G↾C = LC = LSG↾S S! S? C? C! LC = LS = : "views" of the protocol [Honda et al., 2008]
  • 11.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 11 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is ✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢ "well-formed": protocol G iswf(G) ✔ G = C → S. S → C.end deadlock-free G↾C = LC = LSG↾S S! S? C? C! LC = LS = : "views" of the protocol deadlock-free! [Honda et al., 2008]
  • 12.
    deadlock-free? Multiparty Session Types(MPSTs): Protocol-based deadlock freedom 12 C S a "ping" protocol ③ Give concurrent processes (programs) and check their types ① Write a Global Type and check it ② Derive Local Types by End Point Projection (↾) PC | PS The system PC | PS is ✔✔ : "these processes respect the protocol"PSPC LS ⊢LC ⊢ "well-formed": protocol G iswf(G) ✔ G = C → S. S → C.end deadlock-free G↾C = LC = LSG↾S S! S? C? C! LC = LS = : "views" of the protocol deadlock-free! [Honda et al., 2008] How to implement MPSTs in a programming language? Question
  • 13.
    ③ LC ⊢PC ? Go Thread State of the art: Deadlock freedom via code generation 13 ① wf(G) ? ② G↾C Global Protocol File Go Thread Go Thread In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]:
  • 14.
    ③ LC ⊢PC ? Go Thread State of the art: Deadlock freedom via code generation 14 ① wf(G) ? ② G↾C Global Protocol File Go Thread Go Thread In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]: deadlock-free (Well-formedness checking and End Point Projection) Go type (Generated code) Go type (Generated code) Go type (Generated code) Code generation ✔
  • 15.
    ③ LC ⊢PC ? Type checking by Go compiler ✔ (type checking to check protocol conformance) Go Thread State of the art: Deadlock freedom via code generation 15 ① wf(G) ? ② G↾C Global Protocol File Go Thread Go Thread In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]: deadlock-free (Well-formedness checking and End Point Projection) Go type (Generated code) Go type (Generated code) Go type (Generated code) Code generation ✔
  • 16.
    ③ LC ⊢PC ? Type checking by Go compiler ✔ (type checking to check protocol conformance) Go Thread State of the art: Deadlock freedom via code generation 16 ① wf(G) ? ② G↾C Global Protocol File Go Thread Go Thread In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]: deadlock-free (Well-formedness checking and End Point Projection) Go type (Generated code) Go type (Generated code) Go type (Generated code) Code generation ✔ deadlock-free
  • 17.
    ③ LC ⊢PC ? Type checking by Go compiler ✔ (type checking to check protocol conformance) Go Thread State of the art: Deadlock freedom via code generation 17 ① wf(G) ? ② G↾C Global Protocol File Go Thread Go Thread In a MPST toolchain for programming language Go [D. Castro et al., POPL 2019]: deadlock-free (Well-formedness checking and End Point Projection) Go type (Generated code) Go type (Generated code) Go type (Generated code) Code generation ✔ deadlock-free Is it possible to implement MPSTs without code generation? Question
  • 18.
    ③ LC ⊢PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 18 Yes (!) How?
  • 19.
    ↓ A singleOCaml program code file (.ml) OCaml Thread OCaml Thread OCaml Thread Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 19 Yes (!) How?
  • 20.
    ↓ A singleOCaml program code file (.ml) OCaml Thread OCaml Thread OCaml Thread Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 20 ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Yes (!) How?
  • 21.
    ↓ A singleOCaml program code file (.ml) OCaml Thread OCaml Thread OCaml Thread Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 21 Type checking by OCaml compiler ✔ ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Yes (!) How?
  • 22.
    ↓ A singleOCaml program code file (.ml) OCaml Thread OCaml Thread OCaml Thread Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 22 Type checking by OCaml compiler ✔ ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Yes (!) deadlock-free! How?
  • 23.
    ↓ A singleOCaml program code file (.ml) OCaml Thread OCaml Thread OCaml Thread Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom solely by Types! 23 Type checking by OCaml compiler ✔ ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Yes (!) deadlock-free! How? How/why do they work??
  • 24.
    Global Combinators andwell-formedness check 24 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a
  • 25.
    Global Combinators andwell-formedness check 25 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a
  • 26.
    Global Combinators andwell-formedness check 26 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a
  • 27.
    Global Combinators andwell-formedness check 27 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish)) choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2 Example: Adding a branch to Simple OAuth protocol (a few plumbings needed to convince the type checker) Each branch must begin from s
  • 28.
    Global Combinators andwell-formedness check 28 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish)) choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2 NB: Branching in a protocol is a source of concurrency issues (a few plumbings needed to convince the type checker)
  • 29.
    Global Combinators andwell-formedness check 29 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish)) choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2 NB: Branching in a protocol is a source of concurrency issues (a few plumbings needed to convince the type checker) Non-determinism/ Deadlock in a protocol a
  • 30.
    Global Combinators andwell-formedness check 30 ① wf(G) ✔ let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) (r1 --> r2) lab : send a label lab from r1 to r2 (with possible payloads) Example: Simple OAuth protocol s c a let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish)) choice_at r g1 g2 : decide a protocol branching at r, between g1 and g2 NB: Branching in a protocol is a source of concurrency issues (a few plumbings needed to convince the type checker) … is reported as a type error Non-determinism/ Deadlock in a protocol a
  • 31.
    (Deadlock and typeerrors: An analysis) 31 let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish))a poke a instead of c The MPST theory rejects it: they are not "mergeable". Forming a "mixed choice" (which causes nondeterminism) c's first action is input from s c's first action is output to a
  • 32.
    Deriving local typesvia type inference OCaml infers Local Types from global combinators. 32 ② G↾C let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) Example (again): Simple OAuth protocol s c a All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2):
  • 33.
    Deriving local typesvia type inference OCaml infers Local Types from global combinators. 33 ② G↾C let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) Example (again): Simple OAuth protocol s c a All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2): val oauth : [ `cons of < role_C : < login : ('a * close) out lin > > * [ `cons of < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > * [ `cons of < role_C : [> `password of 'b * < role_C : < auth : ('c * close) out lin > > ] inp lin > * ([ `cons of close * 'x ] as 'x) ] ] ] Seq.t c!login s?login a!pass a?auth s!pass s?auth s c a
  • 34.
    Deriving local typesvia type inference OCaml infers Local Types from global combinators. 34 ② G↾C let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) Example (again): Simple OAuth protocol s c a All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2): val oauth : [ `cons of < role_C : < login : ('a * close) out lin > > * [ `cons of < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > * [ `cons of < role_C : [> `password of 'b * < role_C : < auth : ('c * close) out lin > > ] inp lin > * ([ `cons of close * 'x ] as 'x) ] ] ] Seq.t c!login s?login a!pass a?auth s!pass s?auth s c a Destination role's names are a method of an object < role_S < role_A < role_A
  • 35.
    Deriving local typesvia type inference OCaml infers Local Types from global combinators. 35 ② G↾C let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) Example (again): Simple OAuth protocol s c a All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2): val oauth : [ `cons of < role_C : < login : ('a * close) out lin > > * [ `cons of < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > * [ `cons of < role_C : [> `password of 'b * < role_C : < auth : ('c * close) out lin > > ] inp lin > * ([ `cons of close * 'x ] as 'x) ] ] ] Seq.t c!login s?login a!pass a?auth s!pass s?auth s c a Output labels are methods in an object < password Destination role's names are a method of an object < role_S < role_A < role_A
  • 36.
    Deriving local typesvia type inference OCaml infers Local Types from global combinators. 36 ② G↾C let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) Example (again): Simple OAuth protocol s c a All local types are inferred at once, as a cons-list of structural types (here, s=0, c=1, a=2): val oauth : [ `cons of < role_C : < login : ('a * close) out lin > > * [ `cons of < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > * [ `cons of < role_C : [> `password of 'b * < role_C : < auth : ('c * close) out lin > > ] inp lin > * ([ `cons of close * 'x ] as 'x) ] ] ] Seq.t c!login s?login a!pass a?auth s!pass s?auth s c a Input labels are (polymorphic) variant type tags [ `login [ `auth Output labels are methods in an object < password Destination role's names are a method of an object < role_S < role_A < role_A
  • 37.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 37 ③ LC ⊢ PC ✔
  • 38.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 38 < role_S Select destination role via method invocation (#) role_S ③ LC ⊢ PC ✔
  • 39.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 39 < role_S Select destination role via method invocation (#) role_S ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload
  • 40.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 40 < role_S Select destination role via method invocation (#) role_S ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload "Next" channel is supplied as a part of the returned value
  • 41.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 41 < role_S Select destination role via method invocation (#) role_S < role_A role_A ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload "Next" channel is supplied as a part of the returned value
  • 42.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 42 < role_S Select destination role via method invocation (#) role_S < role_A role_A ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload "Next" channel is supplied as a part of the returned value < password #password Select an output label via method invocation (#), then send it with a payload
  • 43.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 43 < role_S Select destination role via method invocation (#) role_S < role_A role_A role_A < role_A ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload "Next" channel is supplied as a part of the returned value < password #password Select an output label via method invocation (#), then send it with a payload
  • 44.
    let ch =get_ch c oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch Protocol conformance via OCaml's type checking 44 < role_S Select destination role via method invocation (#) role_S < role_A role_A `auth [ `auth role_A < role_A ③ LC ⊢ PC ✔ [ `login `login … and receive on it, then pattern-match the value against variant tags (labels) received payload "Next" channel is supplied as a part of the returned value < password #password Select an output label via method invocation (#), then send it with a payload
  • 45.
    let ch =get_ch s oauth (* get a MPST channel for s *) val ch : < role_S : [> `login of 'a * < role_A : < password : ('b * < role_A : [> `auth of 'c * close ] inp lin >) out lin > > ] inp lin > OCaml> let oauth = (s --> c) login ((c --> a) password ((a --> c) auth finish)) let thread_C () = match receive ch#role_S with | `login((u:string), ch)-> let ch = send ch#role_A#password "asdf" in match receive ch#role_A with | `auth((b:bool), ch) -> close ch 45 Protocol conformance via OCaml's type checking③ LC ⊢ PC ✔ ro If there is a typo … OCaml reports a type error at this point
  • 46.
    ↓ A singleOCaml Source code file (.ml) OCaml Program OCaml Program OCaml Program Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom by Types! 46 Type checking by OCaml compiler ✔ ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Recap deadlock-free!
  • 47.
    ↓ A singleOCaml Source code file (.ml) OCaml Program OCaml Program OCaml Program Protocol in OCaml ③ LC ⊢ PC ? ① wf(G) ? ② G↾C Global Protocol Combinator : Deadlock freedom by Types! 47 Type checking by OCaml compiler ✔ ✔ deadlock-free OCaml types OCaml types OCaml types Type checking & inference Recap deadlock-free! Are they really correct??
  • 48.
    GPC: Are theycorrect 48 A. Key idea: Global Combinators pre-generate channels ❖ Multiparty channels as nested sequence of simply-typed channels B. Formalisation of GPC with Deadlock-freedom Theorem ❖ OCamlM: A minimal concurrent language ❖ Typing rules for Global Combinators C. Implementation: GPC as a typed DSL in OCaml ❖ Based on a set of type manipulation techniques (GADTs, field label encoding, and plumbings such as polymorphic record extension) GPC key ingredients
  • 49.
    GPC: Are theycorrect 49 A. Key idea: Global Combinators pre-generate channels ❖ Multiparty channels as nested sequence of simply-typed channels B. Formalisation of GPC with Deadlock-freedom Theorem ❖ OCamlM: A minimal concurrent language ❖ Typing rules for Global Combinators C. Implementation: GPC as a typed DSL in OCaml ❖ Based on a set of type manipulation techniques (GADTs, label encoding, and plumbings such as polymorphic record extension) GPC key ingredients
  • 50.
    50 Let's start cooking!! A.Key idea: Global Combinators pre-generate channels
  • 51.
    A. Key idea:Global Combinators pre-generate channels 51 S C A ⟨⟩ ⟨⟩ ⟨⟩ let oAuth = finish
  • 52.
    A. Key idea:Global Combinators pre-generate channels 52 S C A Sauth ⟨?Sauth⟩ ⟨!Sauth⟩ ⟨⟩ let oAuth = (A → C) auth finish
  • 53.
    A. Key idea:Global Combinators pre-generate channels 53 let oAuth = (C → A) password ((A → C) auth finish) S C A Sauth Spasswd ⟨!Spasswd; ?Sauth⟩ ⟨?Spasswd; !Sauth⟩ ⟨⟩
  • 54.
    A. Key idea:Global Combinators pre-generate channels 54 let oAuth = (S → C) login ((C → A) password ((A → C) auth finish)) S C A ⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩ Sauth Spasswd Slogin ⟨!Slogin ⟩
  • 55.
    A. Key idea:Global Combinators pre-generate channels 55 let oAuth = (S → C) login ((C → A) password ((A → C) auth finish)) S C A ⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩ Sauth Spasswd Slogin ⟨!Slogin ⟩
  • 56.
    Distribute them andstart the communication 56 PS PC PA !Slogin.0| ?Slogin ; !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0
  • 57.
    Distribute them andstart the communication 57 PS PC PA 0| !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0
  • 58.
    Distribute them andstart the communication 58 PS PC PA 0| ?Sauth.0| !Sauth.0
  • 59.
    Distribute them andstart the communication 59 PS PC PA 0| 0| 0
  • 60.
    Distribute them andstart the communication 60 PS PC PA !Slogin.0| ?Slogin ; !Spasswd; ?Sauth.0| ?Spasswd;!Sauth.0 ❖ All these channels are simply-typed (hence no type-errors) ❖ Global combinators aim to be deadlock-free ❖ The nested structure enforces usage order Point
  • 61.
    GPC: Are theycorrect? (cont.) 61 A. Key idea: Global Combinators pre-generate channels ❖ Multiparty channels as nested sequence of simply-typed channels B. Formalisation of GPC (with Deadlock-freedom Theorem) ❖ OCamlM: A minimal concurrent language ❖ Typing rules for Global Combinators (with hints to OCaml DSL) ❖ Session Type merging C. Implementation: GPC as a typed DSL in OCaml ❖ Based on a set of type manipulation techniques (GADTs, field label encoding, and plumbings such as polymorphic record extension) GPC key ingredients
  • 62.
    B. OCamlM: Formalisationof GPC with Deadlock-freedom Theorem • A minimal concurrent language with structural subtyping, equi-recursive types and simply-typed channels • Typing rules for global combinators 62
  • 63.
    Typing rules 63 p1 pn …… … Point: give an index for each role (and order roles) wf(G) ✔, G↾C
  • 64.
    The typing rulefor (-->) 64 p1 pn … pi pj … … wf(G) ✔, G↾C i
  • 65.
    The typing rulefor (-->) 65 p1 pn … pi pj … … Index-based type update wf(G) ✔, G↾C i
  • 66.
    The typing rulefor (-->) 66 p1 pn … pi pj … … Index-based type update p1 pn … pi pj … … "Wrap" with opponent's role names and labels wf(G) ✔, G↾C i
  • 67.
    The typing rulefor (-->) 67 p1 pn … pi pj … … Index-based type update p1 pn … pi pj … … "Wrap" with opponent's role names and labels Implement them by using GADTs and polymorphic lens (explained later) available in OCaml wf(G) ✔, G↾C i
  • 68.
    The typing rulefor (-->) 68 p1 pn … pi pj … … Index-based type update p1 pn … pi pj … … "Wrap" with opponent's role names and labels Requires first-class record fields (methods) and variant tags ⇒ Encode them as values encode it in OCaml Implement them by using GADTs and polymorphic lens (explained later) available in OCaml wf(G) ✔, G↾C i
  • 69.
    The typing rulefor branching (choice_at) 69 wf(G) ✔, G↾C
  • 70.
    The typing rulefor branching (choice_at) 70 Ensure that pa is a sending wf(G) ✔, G↾C
  • 71.
    The typing rulefor branching (choice_at) 71 Ensure that pa is a sending Output labels must be disjoint (deterministic) wf(G) ✔, G↾C
  • 72.
    The typing rulefor branching (choice_at) 72 Ensure that pa is a sending Output labels must be disjoint (deterministic) Merge two records (objects) into one wf(G) ✔, G↾C
  • 73.
    The typing rulefor branching (choice_at) 73 Ensure that pa is a sending Output labels must be disjoint (deterministic) Merge two records (objects) into one Encode disjoint record merging encode it in OCaml wf(G) ✔, G↾C
  • 74.
    The typing rulefor branching (choice_at) 74 wf(G) ✔, G↾C Too restrictive for communication protocols Solution: Subtyping! Requires each role having the same type (behaviour) in each branch → seems standard wrt. if-then-else construct, but
  • 75.
    The typing rulefor branching (choice_at) 75 wf(G) ✔, G↾C Too restrictive for communication protocols Solution: Subtyping! Row polymorphism (objects and polymorphic variants) available in OCaml Requires each role having the same type (behaviour) in each branch → seems standard wrt. if-then-else construct, but
  • 76.
    Typing rules 76 … p1 pn … pi … p1pn … pi … p1 pn … pi … Γ ⊢ choice … {g1; g2} : ⋯×p&{m1:T1, m2:T2}×⋯ Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g2 : ⋯×p&{m2:T2}×⋯ Desired type (According to Full Merging in MPST) A problem: p&{m1:T1} ≠ p&{m2:T2}
  • 77.
    Typing rules 77 … p1 pn … pi … p1pn … pi … p1 pn … pi … Γ ⊢ choice … {m1:g1; m2:g2} : ⋯×p&{m1:T1, m2:T2}×⋯ Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g1 : ⋯×p&{m2:T2}×⋯ ? ?
  • 78.
    Typing rules 78 … p1 pn … pi … p1pn … pi … p1 pn … pi … Γ ⊢ g1 : ⋯×p&{m1:T1, m2:T2}×⋯ Γ ⊢ g2 : ⋯×p&{m1:T1, m2:T2}×⋯ Γ ⊢ g1 : ⋯×p&{m1:T1}×⋯ Γ ⊢ g1 : ⋯×p&{m2:T2}×⋯ Γ ⊢ choice … {g1; g2} : ⋯×p&{m1:T1, m2:T2}×⋯ p&{m1:T1} ≤ p&{m1:T1; m2:T2} p&{m2:T2} ≤ p&{m1:T1; m2:T2} Subtyping!!
  • 79.
    Deadlock and typeerrors: An analysis 79 let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish))a poke a instead of c The MPST theory rejects it: they are not "mergeable". Forming a "mixed choice" (which causes nondeterminism)
  • 80.
    Deadlock and typeerrors: An analysis 80 let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish))a poke a instead of c The MPST theory rejects it: they are not "mergeable". Forming a "mixed choice" (which causes nondeterminism) c's first action is output to a <a: <quit: !bool*cont2>>
  • 81.
    Deadlock and typeerrors: An analysis 81 let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish))a poke a instead of c The MPST theory rejects it: they are not "mergeable". Forming a "mixed choice" (which causes nondeterminism) c's first action is input from s <s: ?[login_str*cont1]> c's first action is output to a <a: <quit: !bool*cont2>>
  • 82.
    Deadlock and typeerrors: An analysis 82 let oauth_branch = choice_at s (to_c login_or_cancel) (s, (s --> c) login ((c --> a) password ((a --> c) auth finish))) (s, (s --> c) cancel ((c --> a) quit finish))a poke a instead of c The MPST theory rejects it: they are not "mergeable". Forming a "mixed choice" (which causes nondeterminism) c's first action is input from s <s: ?[login_str*cont1]> c's first action is output to a <a: <quit: !bool*cont2>> No least upper bound (common supertype) ⇒ type error No least upper bound (common supertype) ⇒ type error
  • 83.
    A note ontyping 83 <r: ?[lab: T1*T2]> <r: <lab: !T1*T2>> Input and output session types are not symmetric with each other. Why? sok : ?bool, scancel : ?int : ?[ok_(boolו); cancel_(int× …)] (← wanted) Making a multiplexed channel from simply-typed channels
  • 84.
    A note ontyping 84 <r: ?[lab: T1*T2]> <r: <lab: !T1*T2>> Input and output session types are not symmetric with each other. Why? sok : ?bool, scancel : ?int : ?[ok_(boolו); cancel_(int× …)] (← wanted) choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel Concurrent ML (Reppy, 1993) Types are slightly modified, they uses "events" in reality Making a multiplexed channel from simply-typed channels
  • 85.
    A note ontyping 85 <r: ?[lab: T1*T2]> <r: <lab: !T1*T2>> Input and output session types are not symmetric with each other. Why? sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] : ?[ok_(boolו); cancel_(int× …)] (← wanted) choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel Concurrent ML (Reppy, 1993) Types are slightly modified, they uses "events" in reality Making a multiplexed channel from simply-typed channels
  • 86.
    A note ontyping 86 <r: ?[lab: T1*T2]> <r: <lab: !T1*T2>> Input and output session types are not symmetric with each other. Why? sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel) : List[ ?[ok_(boolו), cancel_(int×…)] ] : ?[ok_(boolו); cancel_(int× …)] (← wanted) choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel Concurrent ML (Reppy, 1993) Types are slightly modified, they uses "events" in reality Making a multiplexed channel from simply-typed channels
  • 87.
    A note ontyping 87 <r: ?[lab: T1*T2]> <r: <lab: !T1*T2>> Input and output session types are not symmetric with each other. Why? sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel) : List[ ?[ok_(boolו), cancel_(int×…)] ] choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)) : ?[ok_(boolו); cancel_(int× …)] (← wanted) choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel Concurrent ML (Reppy, 1993) Types are slightly modified, they uses "events" in reality Making a multiplexed channel from simply-typed channels
  • 88.
    GPC: Are theycorrect? (cont.) 88 A. Key idea: Global Combinators pre-generate channels ❖ Multiparty channels as nested sequence of simply-typed channels B. Formalisation of GPC (with Deadlock-freedom Theorem) ❖ OCamlM: A minimal concurrent language ❖ Typing rules for Global Combinators (with hints to OCaml DSL) ❖ Session Type merging C. Implementation: GPC as a typed DSL in OCaml ❖ Based on a set of type manipulation techniques (GADTs, field label encoding, and details of plumbings for polymorphic record extension) ❖ Benchmarks: Garbage collection matters ❖ Linearity monad GPC key ingredients Please ask me over beer!
  • 89.
    GPC wrap up 89 GlobalProtocol Combinator: a DSL for writing global protocols ❖ Key Ingredients: Global Combinators ❖ Covers all basic MPST features (including full merging) ❖ Extensions: HTTP, and OAuth Example (on top of it), and more OCamlM: fomalisation of a minimal programming language for GPC ❖ Subject Reduction, Operational Correspondence and Deadlock-freedom ❖ Types for global combinators ❖ Merging is a least upper bound in subtyping relation Sauth Spasswd let oauth = (s --> c) login … p1 pn … … …
  • 90.
    Future Work 90 A →B B → C A → B • Deadlock-freedom proof on full global combinators ❖ Including more expressive ones (e.g. relaxed loop conditions) ❖ Scatter/Gather (broadcast), undirected internal choice, … • Implementation in other programming languages ❖ TypeScript (structural subtyping from beginning, and will have recursive types as well) ❖ Haskell (automatically construct global combinators via type classes) Thank you!
  • 91.
  • 92.
    Loops are easy(for now) 92 let oAuth = (S → C) login ((C → A) password ((A → C) auth finish)) S C A ⟨?Slogin ; !Spasswd; ?Sauth.0 ⟩ ⟨?Spasswd; !Sauth⟩ Sauth Spasswd Slogin ⟨?Slogin ⟩
  • 93.
    Loops are easy(for now) 93 let oAuth = fix (λx. (S → C) login ((C → A) password ((A → C) auth x)) S C A μx.⟨?Slogin ; !Spasswd; ?Sauth; x ⟩ μx. ⟨?Spasswd; !Sauth; x⟩ Sauth Spasswd Slogin μx. ⟨?Slogin; x⟩
  • 94.
    Branchings? 94 S C A Sauth Spasswd Slogin (S → C)login ((C → A) password ((A → C) auth finish)) (S → C) cancel ((C → A) quit finish) S C A Squit Scancel +?
  • 95.
    Input / outputprimitives and row-polymorphism in OCaml 95 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch (FP's type inference-friendly structural typing)
  • 96.
    Input / outputprimitives and row-polymorphism in OCaml 96 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants
  • 97.
    Input / outputprimitives and row-polymorphism in OCaml 97 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants Output labels are methods in an object (fields in a polymorphic record) Output labels are methods in an object (fields in a polymorphic record)
  • 98.
    Input / outputprimitives and row-polymorphism in OCaml 98 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch OCaml's row-polymorphism simulates session-type subtyping (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants Output labels are methods in an object (fields in a polymorphic record) Output labels are methods in an object (fields in a polymorphic record)
  • 99.
    Input / outputprimitives and row-polymorphism in OCaml 99 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch OCaml's row-polymorphism simulates session-type subtyping (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants Output labels are methods in an object (fields in a polymorphic record) Output labels are methods in an object (fields in a polymorphic record) val ch : < role_C : [< `password of string * < role_C : < auth : (bool * close) out lin; .. >; .. > ] inp lin; .. > -> unit
  • 100.
    Input / outputprimitives and row-polymorphism in OCaml 100 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch OCaml's row-polymorphism simulates session-type subtyping (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants Output labels are methods in an object (fields in a polymorphic record) Output labels are methods in an object (fields in a polymorphic record) val ch : < role_C : [< `password of string * < role_C : < auth : (bool * close) out lin; .. >; .. > ] inp lin; .. > -> unit Inferred polymorphic variant type: it can have less receiving labels (= in this case it must have password at least since there must be one)
  • 101.
    Input / outputprimitives and row-polymorphism in OCaml 101 let thread_A () = let `password((p:string), ch) = receive ch#role_C in let ch = send ch#role_C#auth true in close ch OCaml's row-polymorphism simulates session-type subtyping (FP's type inference-friendly structural typing) Input labels are polymorphic variants Input labels are polymorphic variants Output labels are methods in an object (fields in a polymorphic record) Output labels are methods in an object (fields in a polymorphic record) val ch : < role_C : [< `password of string * < role_C : < auth : (bool * close) out lin; .. >; .. > ] inp lin; .. > -> unit Inferred polymorphic variant type: it can have less receiving labels (= in this case it must have password at least since there must be one) Inferred object type: it can have more sending labels
  • 102.
    Branching 102 let oauth1 = choice_ats (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> c) cancel @@ (c --> a) quit finish) A protocol with branching: let thread_C () = match receive ch#role_S with | `cancel((code:int), ch) -> close (send chc#role_A#quit ()) | `login((), ch) -> let ch = send ch#role_A#password "asdf" in let `auth(b, ch) = receive ch#role_A in close ch Code for C (waiting for S with an external choice):
  • 103.
    Branching 103 let oauth1 = choice_ats (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> c) cancel @@ (c --> a) quit finish) A protocol with branching: S will decide a branch, then C and A will follow let thread_C () = match receive ch#role_S with | `cancel((code:int), ch) -> close (send chc#role_A#quit ()) | `login((), ch) -> let ch = send ch#role_A#password "asdf" in let `auth(b, ch) = receive ch#role_A in close ch Code for C (waiting for S with an external choice):
  • 104.
    Branching 104 let oauth1 = choice_ats (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> c) cancel @@ (c --> a) quit finish) A protocol with branching: S will decide a branch, then C and A will follow let thread_C () = match receive ch#role_S with | `cancel((code:int), ch) -> close (send chc#role_A#quit ()) | `login((), ch) -> let ch = send ch#role_A#password "asdf" in let `auth(b, ch) = receive ch#role_A in close ch Code for C (waiting for S with an external choice):An external choice is a pattern matching (idiomatic OCaml)
  • 105.
    Loops and delegations(1) 105 let oauth2 = fix (fun self -> choice_at s (to_c login_cancel_or_retry) (s, oauth1 ()) (s, (s --> c) retry @@ (c --> a) retry self)) Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default), programmers can handle recursions very naturally:
  • 106.
    Loops and delegations(1) 106 let oauth2 = fix (fun self -> choice_at s (to_c login_cancel_or_retry) (s, oauth1 ()) (s, (s --> c) retry @@ (c --> a) retry self)) recursionrecursion Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default), programmers can handle recursions very naturally:
  • 107.
    Loops and delegations(1) 107 let oauth2 = fix (fun self -> choice_at s (to_c login_cancel_or_retry) (s, oauth1 ()) (s, (s --> c) retry @@ (c --> a) retry self)) recursionrecursion protocol reuse Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default), programmers can handle recursions very naturally:
  • 108.
    Loops and delegations(1) 108 let oauth2 = fix (fun self -> choice_at s (to_c login_cancel_or_retry) (s, oauth1 ()) (s, (s --> c) retry @@ (c --> a) retry self)) recursionrecursion protocol reuse val ch_S : < role_C : < cancel : ('_b * close) out lin; login : ('_c * close) out lin; retry : ('_d * 'a) out lin > > as 'a OCaml> Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default), programmers can handle recursions very naturally:
  • 109.
    Loops and delegations(1) 109 let oauth2 = fix (fun self -> choice_at s (to_c login_cancel_or_retry) (s, oauth1 ()) (s, (s --> c) retry @@ (c --> a) retry self)) recursionrecursion protocol reuse val ch_S : < role_C : < cancel : ('_b * close) out lin; login : ('_c * close) out lin; retry : ('_d * 'a) out lin > > as 'a OCaml> recursionrecursion Thanks to OCaml's equi-recursive types (built in polymorphic variants and objects by default), programmers can handle recursions very naturally:
  • 110.
    Loops and delegations(2) 110 let oauth_deleg = (mst --> wrk) (msg >: get_prot s oauth2) finish Delegation doesn't need any special treatment, since OCaml will just infer the delegated type. However, you can annotate labels with a delegated protocol, like this: val ch_Mst : < role_Wrk : < msg : (< role_C : < cancel : ('_b * close) out lin; login : ('_c * close) out lin; retry : ('_d * 'a) out lin > > as 'a * close) out lin > > OCaml> Delegated type
  • 111.
    Detecting protocol errorsusing types 111 Non-determinism/ Deadlock in a protocol let oauth1 = choice_at s (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> a) cancel @@ (c --> a) quit finish) NB: Branching is a source of concurrency issues
  • 112.
    Detecting protocol errorsusing types 112 Non-determinism/ Deadlock in a protocol let oauth1 = choice_at s (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> a) cancel @@ (c --> a) quit finish) … is also reported as a type error NB: Branching is a source of concurrency issues
  • 113.
    Detecting protocol errorsusing types 113 Non-determinism/ Deadlock in a protocol let oauth1 = choice_at s (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> a) cancel @@ (c --> a) quit finish) … is also reported as a type error Theorem: if a global type G is well-formed, its encoding to a global combinator g =⟦G⟧ is well-typed in OCamlM. NB: Branching is a source of concurrency issues
  • 114.
    Detecting protocol errorsusing types 114 Non-determinism/ Deadlock in a protocol let oauth1 = choice_at s (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> a) cancel @@ (c --> a) quit finish) … is also reported as a type error Theorem: if a global type G is well-formed, its encoding to a global combinator g =⟦G⟧ is well-typed in OCamlM. NB: Branching is a source of concurrency issues Global Combinators have full expressivity of MPST Global Types
  • 115.
    [Formalisation] OCamlM :a Minimal calculus for global combinators Main results: 115 A calculus with structural subtyping, equi-recursive types and i/o-typed channels Theorem (Subject Reduction): if ⊢ e and e→* e' then ⊢ e' Theorem (Operational Correspondence): (Completeness) (Soundness) Corollary (Deadlock Freedom): If an MPST process P is deadlock-free, OCamlM expression e=⟦P⟧ is deadlock-free.
  • 116.
    Other features andExamples ✔ Branchings, loops, delegations ❖ Allows full merging in a branching (next slide) ✔ MPST as a wrapper ❖ Offers global protocol on top of HTTP, DNS, … ❖ Example: OAuth, DNS server, SMTP client, … ❖ Utilise concurrent/distributed libraries: Lwt (lightweight threads) and Unix IPC ✔ More Extensions ❖ Scatter/Gather (broadcast) ❖ Undirected choice (-nolive) ❖ Unbalanced Loops 116 B⊕m1 C⊕m2 B⊕m1C⊕m2 A → B B → C A → B
  • 117.
    Full merging 117 let oauth1= choice_at s (to_c login_or_cancel) (s, (s --> c) login @@ (c --> a) password @@ (a --> c) auth finish) (s, (s --> c) cancel @@ (c --> a) quit finish) Input labels are polymorphic variantsA can have different input branches Example: A branch happens between S and C. ⇒ Merge A's two behaviours into one Merging strategy Synopsis Implementations Plain merging All branches must have same labels/continuation (restrictive) Scalas et al. (ECOOP 2017) ✔ Full merging Different input labels/continuations can be mergeable (more relaxed) This work
  • 118.
    • Benchmarks reflectour design decision to use mutable long lived objects (e.g channel vectors) ❖ Our work: few mutable long lived objects, created at the start of the protocol ❖ State-of-the-art (linear-decomposition [Scala et.a]): many small channels, created on-demand (during the protocol execution) 118
  • 119.
    Benchmarks • Comparison withLinear (Binary) Decomposition [Scalas et al., 2017] ❖ Translation from MPST to Linear Types ❖ Continuation Passing Style (CPS): It creates (and exchanges) a fresh channel at each communication step ❖ Must be slower than us?? • Compete with ours in some cases (!), but CPS is slower in general ❖ OCaml's major GC is doing nice work • Monad (static linearity checking with overhead) VS. Direct style (dynamic) 119
  • 120.
    Put All Slidesin right contexts!! • Most surprising parts: • (what is it) 簡単に? programmers can write like this… select opponent role by method, then (a) send by method / (b) receive it and pattern match on variants. Errors are detected like this… GC well-formedness errors and Local type conformance errors. Bonus: recursive sessions, session subtyping and delegations are all free. • (why/how gc-like typing is possible??) (1) (why EPP is possible, it is operation on types!!: see onion and --> typing.) (2) (why well-formedness checking is possible? What is well-formedness?: see typing rules) • (key idea) タマネギ.2枚くらいにおさめる • (how it is typed) --> typing and implementation (mention that OCaml do not have such first-class?) • (how deadlock is detected: harder) choice, nondeterminisim and deadlock choice is like an if-then-else. Two branches are merged into one. (Sub)typing and global combinator typing prevents occasional wrong branching. • (how it is imlpemented) lenses and first class record fields • Choice_at typing and record extensions ❖ Least upper bound is merging ❖ We have more expressive GTs ❖ Subtyping and equi-recursive types ❖ Unguardedness and Unbalanced merging • Linearity monad • Deadlock freeness, syntax of local types, and undirected choice (sending and receiving) • Benchmarks • Meaning of type errors and relationship to deadlocks ❖ Mergeability and local type syntax ❖ Possibility to extension (i.e. non-directed merging) ❖ Why roles are record fields – what if it was variant tags 120
  • 121.
    Channel Vectors: InhabitingMPSTs as simple channel types 121 TA = B⊕{ok.•; cancel.B&cancel.•} TB = A&{ok.•; cancel.B⊕cancel.•}
  • 122.
    Channel Vectors: InhabitingMPSTs as simple channel types 122 sok scancel1 scancel2 sok scancel1 scancel2 Idea: Put simply-typed channels in a tree-like data structure TA = B⊕{ok.•; cancel.B&cancel.•} TB = A&{ok.•; cancel.B⊕cancel.•}
  • 123.
    Internal Choice isRecord A record having pairs of an output channel and "the rest" in its fields 123 ⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s = <B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> > Pictorially:
  • 124.
    Internal Choice isRecord A record having pairs of an output channel and "the rest" in its fields 124 ⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s = <B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> > (scancel, )(sok, ) … ok cancel Pictorially:
  • 125.
    Internal Choice isRecord A record having pairs of an output channel and "the rest" in its fields 125 ⟦ B⊕{ok.•; cancel.B&cancel(int).•} ⟧s = : ⟨B : ⟨ok: !(int*int)ו; cancel: !(bool) ×⟦…⟧⟩ ⟩ Provided that • sok : Och, scancel : Och (! is an output channel type) <B = <ok= (sok, •); cancel= (scancel1, ⟦...⟧s)> > (scancel, )(sok, ) … ok cancel Pictorially:
  • 126.
    External choice isvariant input 126 Variant input type: ?[ok_(boolו); cancel_(int× …)] Variant type: [ok_(boolו); cancel_(int× …)] ("Either ok (with boolו) or cancel (with int×…)") ("Receives either ok (with boolו) or cancel (with int×…)") cancel(_, )ok(_, ) scancel1sok cancel external choice Pictorially: But how?
  • 127.
    A Solution fromConcurrent ML (Reppy, 1993) 127 … has a set of (event) primitives we need! choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel sok : ?bool, scancel : ?int : ?[ok_(boolו); cancel_(int× …)] (← wanted)
  • 128.
    A Solution fromConcurrent ML (Reppy, 1993) 128 … has a set of (event) primitives we need! choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] : ?[ok_(boolו); cancel_(int× …)] (← wanted)
  • 129.
    A Solution fromConcurrent ML (Reppy, 1993) 129 … has a set of (event) primitives we need! choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel) : List[ ?[ok_(boolו), cancel_(int×…)] ] : ?[ok_(boolו); cancel_(int× …)] (← wanted)
  • 130.
    A Solution fromConcurrent ML (Reppy, 1993) 130 … has a set of (event) primitives we need! choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel) : List[ ?[ok_(boolו), cancel_(int×…)] ] choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)) : ?[ok_(boolו); cancel_(int× …)] (← wanted)
  • 131.
    A Solution fromConcurrent ML (Reppy, 1993) 131 … has a set of (event) primitives we need! choose : List[?T] -> ?T makes a (multiplexed) channel (external choice) wrap : (α -> β) -> ?α -> ?β makes a wrapped channel sok : ?bool, scancel : ?int wrap (λx.[ok=(x,•)]) sok : ?[ok_(boolו)] wrap (λx.[cancel=(x,…)]) scancel : ?[cancel_(int×…)] List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel) : List[ ?[ok_(boolו), cancel_(int×…)] ] choose (List(wrap (λx.[ok=(x,•)]) sok; wrap (λx.[cancel=(x,…)]) scancel)) cancel(_, )ok(_, ) scancel1 sok (scancel2, ) cancel choose : ?[ok_(boolו); cancel_(int× …)] (← wanted)
  • 132.
    Putting them altogether 132 (scancel,)(sok, ) ok cancel cancel(_, )ok(_, ) scancel1 sok (scancel2, ) cancel choose B⊕{ok(bool).•; cancel(int).B&cancel(int).•} A&{ok(bool).•; cancel(int).A⊕cancel(int).•} choice_at A {(A → B) ok finish, (A → B) cancel((B → A) cancel finish)} cancel(_, ) scancel2
  • 133.
    Putting them altogether 133 (scancel,)(sok, ) ok cancel cancel(_, )ok(_, ) scancel1 sok (scancel2, ) cancel choose B⊕{ok(bool).•; cancel(int).B&cancel(int).•} A&{ok(bool).•; cancel(int).A⊕cancel(int).•} choice_at A {(A → B) ok finish, (A → B) cancel((B → A) cancel finish)} cancel(_, ) scancel2