Choreographies


What is a choreography?

What is a choreography?

Choreographies are a way of describing communicating systems as global programs

A

🕺🏽

        x = crunch()
        send("B",x)
      

B

🕺

        x = receive("A")
        y = crunch(x)
      

A


        x = crunch()
        send("B",x)
      

B


        x = receive("a")
        y = crunch(x)
        send("A",y)
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
        if y > 100:
          z = crunch(y)
          send("B",z)
        else:
          exit 1
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
        if y > 100:
          z = crunch(y)
          send("B",z)
        else:
          exit 1
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
        if y > 100:
          z = receive("A")
          ...
        else:
          exit 1
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
        z = crunch(y)
        if z > 100:
          send("B",z)
        else:
          exit 1
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
      

?


        let x@A = crunch()
        A[x] -> B.x
        let y@B = crunch(x)
      

A


        x = crunch()
        send("B",x)
      

B


        x = receive("A")
        y = crunch(x)
      

        let x@A = crunch()
        A[x] -> B.x
        let y@B = crunch(x)
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
      

        let x@A = crunch()
        A[x] -> B.x
        let y@B = crunch(x)
        B[y] -> A.y
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
      

B


        x = receive("A")
        y = crunch(x)
        send("A",y)
      

        let x@A = crunch()
        A[x] -> B.x
        let y@B = crunch(x)
        B[y] -> A.y
      

A


        ...
        if y > 100:
          z = crunch(y)
          send("B",z)
        else:
          exit 1
      

B


        ...
        if y > 100:
          z = receive("A")
          ...
        else:
          exit 1
      

        //...
        let v@A = y > 100
        if v@A {
          A<T> -> B
          let z@A = crunch(y)
          A.[z] -> B.z
          //...
        } else {
          A<F> -> B
          //DONE
        }
      

A


        ...
        if y > 100:
          z = crunch(y)
          send("B",z)
        else:
          exit 1
      

B


        ...
        if y > 100:
          z = receive("A")
          ...
        else:
          exit 1
      
🕺🕺🏽

        //...
        let v@A = y > 100
        if v@A {
          A<T> -> B
          let z@A = crunch(y)
          A.[z] -> B.z
          //...
        } else {
          A<F> -> B
          //DONE
        }
      

Syntax

G::= A[x] -> B.y; G(com)
| A<b> -> B; G(sel)
| Let x@A = foo(..); G(let)
| If x@A Then G Else G(if)
| End(end)

Semantics

$(s,c) \xrightarrow{(\tau,l)} (s',c')$


Where:

Communication


A[x] -> B.y;C

Communication


S
A[x] -> B.y;C

Communication


S(A,x) = d
A[x] -> B.y;C

Communication


A[x] -> B.y;C
S[(B,y)|->d]

Communication


S[(B,y)|->d]
C

Features

Concurrency

Concurrency


           A[x] -> B.y
           P[z] -> Q.w
                ✅
        


              A[x] -> B.y
              P[z] -> Q.w
              C[m] -> D.k
          


              A[x] -> B.y
                   ✅
              C[m] -> D.k
          


                ✅
           P[z] -> Q.w
           C[m] -> D.k
        

Asyncrony

Asyncrony


              A[x] -> B.y
              P[z] -> A.w
              A[m] -> D.k
          

Asyncrony


              A[x] -> B.y
              P[z] -> A.w
              A[m] -> D.k
          


                ✅
           P[z] -> A.w
           A[m] -> D.k
          

Asyncrony


              A[x] -> B.y
              P[z] -> A.w
              A[m] -> D.k
          


             ✅ -> B.y
           P[z] -> A.w
           A[m] -> D.k
          


             ✅ -> ✅
           P[z] -> A.w
           A[m] -> D.k
          

Asyncrony


              A[x] -> B.y
              P[z] -> A.w
              A[m] -> D.k
          


                ✅ -> B.y
                   ✅
              A[m] -> D.k
          


                ✅
           P[z] -> A.w
           A[m] -> D.k
          

Asyncrony


             A[x] -> B.y
             P[z] -> A.w
                  ❌
        


              A[x] -> B.y
              P[z] -> A.w
              A[m] -> D.k
          


              A[x] -> B.y
                   ✅
              A[m] -> D.k
          


                ✅
           P[z] -> A.w
           A[m] -> D.k
          

Projection


        let x@A = crunch()
        let y@B = crunch()
        A[x] -> B.x
        B[y] -> A.y
      

        let x@A = crunch()
        let y@B = crunch()
        A[x] -> B.x
        B[y] -> A.y
      

A


        x = crunch()
        

        let x@A = crunch()
        let y@B = crunch()
        A[x] -> B.x
        B[y] -> A.y
      

A


        x = crunch()
        

B


        y = crunch()
        

        let x@A = crunch()
        let y@B = crunch()
        A[x] -> B.x
        B[y] -> A.y
      

A


        x = crunch()
        send("A",x)
        

B


        y = crunch()
        x = receive("A")
        

        let x@a = crunch()
        let y@b = crunch()
        A[x] -> B.x
        B[y] -> A.y
      

A


        x = crunch()
        send("B",x)
        y = receive("B")
        

B


        y = crunch()
        x = receive("A")
        send("A",y)
        

Confluence

Deadlock-freedom

$\text{fv}(c) \subseteq \text{fv}(s) \implies \exists{s'.}{(s,c) \rightarrow^{\ast} (s',end)}$

        A[x] -> B.x
        B[y] -> A.y
      


        A[x] -> B.x
        B[y] -> A.y
      


        A[x] -> B.x
        B[y] -> A.y
      

An endpoint language

EPN::= <p,s,q,EP>(Single)
| <p,s,q,EP> || EPN(Parallel)

Where:

EP::= Send p x; EP
| Receive p y; EP
| InternalChoice p b; EP
| ExternalChoice p EP EP
| Let v f vl in EP
| If v Then EP Else EP
| End

<A,sa,qa,>


        Send "B" x
        ...
      

sa(x) = d

<B,sb,qb,>


        Receive "A" x
        ...
      

<A,sa,qa,>


        ...
      

sa(x) = d

<B,sb,qb',>


        Receive "A" x
        ...
      

qb' = ("A",d)::qb

<A,sa,qa,>


        ...
      

<B,sb',qb,>


        ...
      

sb' = sb[x |-> d]

project(p,c) = (succ,EP)


Where:


    Definition project_def:
    ...
    ∧ project proc (Com p1 v1 p2 v2 c) =
        if proc = p1 ∧ proc = p2
        then (F,Nil)
        else if proc = p1
             then Send p2 v1 <Γ> project proc c
             else if proc = p2
                  then Receive p1 v2 <Γ> project proc c
                  else project proc c
    ...
  

Semantic preservation

$(s,c)\xrightarrow{}(s',c')$
$\exists{c'',s''.\;}(s',c')\rightarrow^{\ast}(s'',c'')\,\land\, [\![s,c]\!]\rightarrow^{\ast}[\![s'',c'']\!]$

Semantic reflection

$[\![s,c]\!]\xrightarrow{}epn$
$\exists{c',s'.\;}epn\rightarrow^{\ast}[\![s',c']\!]\,\land\, (s,c)\rightarrow^{\ast}(s',c')$

EPN

EPN

Selection

Payload


        IntChoice b p
        ...
      


        Let fv = b
        Send p fv
        ...
      

        ExternalChoice p e1 e2
      


        Receive p fv
        If fv Then e1 Else e2
      

        Send p vlm
        ...
      


        Send p v
        Send p l
        Send p m
        ...
      

        Receive p vlm
        ...
      


        Receive p v
        Receive p l
        Receive p m
        ...
      
*Wildly oversimplified

EPN

Selection

Payload