Constraining Delimited Control with Contracts Asumu Takikawa T. Stephen Strickland* Sam Tobin-Hochstadt Northeastern University University of Maryland, College Park* 1
Experienced programmers divide up all significant programs into separate components 2
web server (-> request? response?) request? servlet 3
Import/export is a communication channel between components web server (-> request? response?) request? Executable specifications can protect these channels servlet 4
Powerful control operators are available in virtually every significant language Lua Coroutines Python Generators JavaScript Generators Racket Continuations Ruby Fibers SML Continuations Scala Continuations 5
web server servlet 6
web server servlet 7
web server Control establishes a new communication channel No mechanism exists to protect these channels servlet 8
Problem: Most languages cannot offer expressive interfaces for components that use control operators 9
Our contribution - Contracts to protect control-based communication channels in Racket - Gradual typing for delimited control in Typed Racket 10
Our contribution wcm ccm call/comp abort prompt ∅ Types Contracts Gradual typing 11
Our contribution wcm ccm call/comp abort prompt ∅ Types Contracts Gradual typing 12
Our contribution wcm ccm call/comp abort talk prompt ∅ Types Contracts Gradual typing 13
Contracts in a nutshell 14
Contracts - agreements between two components Basic form: (contract "::1" ipv6? P N) P provides a value "::1" with contract ipv6? to N Value violates contract ⇒ P is blamed (contract "127.0.0.1" ipv6? P N) "Contract violation. Blaming: P" 15
Generalizes to higher-order cases [Findler & Felleisen ICFP 2002] f = (contract ( λ (addr) (ipv4-to-ipv6 addr)) ( → ipv4? ipv6?) P N) Contract on f's domain violated ⇒ N is blamed (f "2a00:1450:400a:804::1012") "Contract violation. Blaming: N" 16
f = (contract ( λ (addr) (ipv4-to-ipv6 addr)) ( → ipv4? ipv6?) P N) λ "2a00:1450:400a:804::1012" 17
g = (contract f ( → ipv4? ipv6?) N P) λ "2a00:1450:400a:804::1012" 18
Control operators 19
Continuations ~ high-level stack API Elements of delimited control [Dybvig et. al JFP 2007] (1) make a delimiter (1) create a tag (2) delimit a continuation (2) mark stack segment with tag ~ (3) capture a continuation (3) store segment in a variable (4) abort a continuation (4) delete part of stack (5) install a continuation (5) append segments onto stack Continuation marks [Clements et al. ESOP 2001] (6) store data in continuation (6) store data in stack 20
Continuations ~ high-level stack API Elements of delimited control [Dybvig et. al JFP 2007] (1) make a delimiter (1) create a tag (2) delimit a continuation (2) mark stack segment with tag ~ (3) capture a continuation (3) store segment in a variable (4) abort a continuation (4) delete part of stack (5) install a continuation (5) append segments onto stack Continuation marks [Clements et al. ESOP 2001] (6) store data in continuation (6) store data in stack 21
% ☆ h delimit % abort delete 22
% ☆ h delimit % ... abort delete 23
% ☆ h delimit % ... abort delete ... 24
% ☆ h delimit % ... abort delete ... ... 25
% ☆ h delimit % ... abort delete ... ... abort ☆ 5 ☆ is a prompt tag that allows communication between stack frames 26
delimit (h 5) % abort delete 27
Interaction of Control & Contracts 28
Design principles A correct contract system should: • offer opportunities to mediate the exchange of values along channels between components • blame a component for contract violations only if it affects the flow of values [Dimoulas Dissertation 2012] [Dimouas et al. ESOP 2012] 29
component A prime? protected channel component B Contracts checked on boundary crossings 30
component A % ☆ h prime? unprotected channel abort ☆ 4 component B abort bypasses usual protection by jumping Same mechanism does not work 31
Key idea Principle 1: • offer opportunities to mediate the exchange of values along channels between components Operations that skip the contract boundary need extra contract mechanism 32
Key idea Principle 1: • offer opportunities to mediate the exchange of values along channels between components Operations that skip the contract boundary need extra contract mechanism Question: how to plug the hole? 33
★ = (contract ☆ (prompt-tag/c prime?) B A) component A % ★ h ★ ☆ abort ☆ 4 component B 34
★ = (contract ☆ (prompt-tag/c prime?) B A) component A % ★ h ★ ☆ abort ☆ 4 component B 35
★ = (contract ☆ (prompt-tag/c prime?) B A) component A % ★ h ★ Blame B ☆ abort ☆ 4 component B prompt has positive party as B 36
The missing mechanism ★ = (contract ☆ (prompt-tag/c prime?) B A) component A % ★ h ★ Blame B The contract on the tag triggers a contract check ☆ abort ☆ 4 component B prompt has positive party as B 37
★ = (contract ☆ (prompt-tag/c prime?) A B) component A % ☆ h ☆ ★ abort ★ 4 component B 38
★ = (contract ☆ (prompt-tag/c prime?) A B) component A % ☆ h ☆ ★ abort ★ 4 component B 39
★ = (contract ☆ (prompt-tag/c prime?) A B) component A % ☆ h ☆ Blame B ★ abort ★ 4 component B abort swaps positive, negative parties 40
Correct blame ★ = (contract ☆ (prompt-tag/c prime?) A B) Principle 2: component A % ☆ h • blame a component for contract violations only if ☆ it affects the flow of values Blame B ★ The abort provides the value but it's the client of a contract. Thus it swaps blame parties abort ★ 4 component B abort swaps positive, negative parties 41
h = ( λ (f) (f 4)) f = ( λ (x) (prime-after x)) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) A B) component A % ☆ h ☆ ★ abort ★ f component B 42
h = ( λ (f) (f 4)) f = ( λ (x) (prime-after x)) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) A B) component A % ☆ h ☆ ★ abort ★ f component B 43
h = ( λ (f) (f 4)) f = ( λ (x) (prime-after x)) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) A B) component A % ☆ h ☆ Blame A ★ abort ★ f component B Delayed contract means blame raised at prompt 44
f B A ctc ctc = (-> prime? prime?) 45
f B A ctc ctc = (-> prime? prime?) 56
f B A ctc ctc = (-> prime? prime?) 67
f B A ctc ctc = (-> prime? prime?) 78
Blame A B A ctc ctc = (-> prime? prime?) 89
h = ( λ (f) (f 7)) f = ( λ (x) 4) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) C A,B) component A % ★ h ★ C ★ C abort ★ f component B Contract triggered from both sides 100
h = ( λ (f) (f 7)) f = ( λ (x) 4) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) C A,B) component A % ★ h ★ C ★ C abort ★ f component B Contract triggered from both sides 101
h = ( λ (f) (f 7)) f = ( λ (x) 4) ★ = (contract ☆ (prompt-tag/c (-> prime? prime?)) C A,B) component A % ★ h ★ C Blame B ★ C abort ★ f component B Contract triggered from both sides 102
f B C A ctc ctc ctc = (-> prime? prime?) 103
f B C A ctc ctc ctc = (-> prime? prime?) 114
f B C A ctc ctc ctc = (-> prime? prime?) 125
f B C A ctc ctc ctc = (-> prime? prime?) 136
f B C A ctc ctc ctc = (-> prime? prime?) 147
f B C A ctc ctc ctc = (-> prime? prime?) 158
Blame B B C A ctc ctc ctc = (-> prime? prime?) 169
Summary A correct contract system should: • offer opportunities to mediate the exchange of values along channels between components • blame a component for contract violations only if it affects the flow of values 1. Trigger contracts via tags to mediate communication 2. Swap blame labels as appropriate for correct blame 180
Conclusion 181
Our contribution wcm ccm call/comp abort talk prompt ∅ Types Contracts Gradual typing 182
Our contribution wcm ccm call/comp abort prompt ∅ Types Contracts Gradual typing 183
Gradual typing requires contracts [Tobin-Hochstadt & Felleisen DLS 2006] [Siek & Taha, Scheme 2006] typed Gradual typing = contract check Type system + Dynamic checking untyped τ → contract 184
☆ : (Prompt Integer Float) typed % ☆ h ☆ ★ abort ★ "a" untyped ★ = (contract ☆ (prompt-tag/c int?) typed untyped) 185
☆ : (Prompt Integer Float) typed % ☆ h ☆ Blame untyped ★ abort ★ "a" untyped ★ = (contract ☆ (prompt-tag/c int?) typed untyped) 186
Further coverage - call/cc fits into this model - operators like shift/reset via macros - could adapt to operators like coroutines 187
Recommend
More recommend