Substructural Typestates Filipe Milito (CMU & UNL) Jonathan - - PowerPoint PPT Presentation

substructural typestates
SMART_READER_LITE
LIVE PREVIEW

Substructural Typestates Filipe Milito (CMU & UNL) Jonathan - - PowerPoint PPT Presentation

Programming Languages meets Program Verification 2014 Substructural Typestates Filipe Milito (CMU & UNL) Jonathan Aldrich (CMU) Lus Caires (UNL) Motivation File file = new File( out.txt ); file


slide-1
SLIDE 1

Substructural Typestates

Filipe Militão (CMU & UNL) Jonathan Aldrich (CMU) Luís Caires (UNL)

Programming Languages meets Program Verification 2014

slide-2
SLIDE 2

Motivation

  • File file = new File( “out.txt” );
  • file.write( “stuff” );
  • file.close();
  • file.write( “more stuff” );

Note: consider a simplified File object, similar to Java’s FileOutputStream.

2

slide-3
SLIDE 3

Motivation

  • File file = new File( “out.txt” );
  • file.write( “stuff” );
  • file.close();
  • file.write( “more stuff” );

FAILS with runtime exception (“invalid file descriptor”)

3

slide-4
SLIDE 4

Motivation

class File { FileDescriptor fd; File( string filename ){ fd = OS.createFile( filename ); } void write( string s ){ if( fd == null ) throw Exception(“invalid file descriptor”); fd.write( s ); } void close(){ fd = null; } }

4

slide-5
SLIDE 5

Motivation

class File { FileDescriptor fd; File( string filename ){ fd = OS.createFile( filename ); } void write( string s ){ if( fd == null ) throw Exception(“invalid file descriptor”); fd.write( s ); } void close(){ fd = null; } }

4

The File type abstraction does not precisely express the changing properties of File’s internal state (fd).

File File File File File

slide-6
SLIDE 6

class File { FileDescriptor fd; File( string filename ){ fd = OS.createFile( filename ); } void write( string s ){ if( fd == null ) throw Exception(“invalid file descriptor”); fd.write( s ); } void close(){ fd = null; } }

Motivation

Open Open Open Closed Open

5

Superfluous if statically ensured to

  • nly be used when File is open.
slide-7
SLIDE 7

class File { FileDescriptor fd; File( string filename ){ fd = OS.createFile( filename ); } void write( string s ){ if( fd == null ) throw Exception(“invalid file descriptor”); fd.write( s ); } void close(){ fd = null; } }

Motivation

Open Open Open Closed Open

5

Superfluous if statically ensured to

  • nly be used when File is open.

Open and Close are typestates.

slide-8
SLIDE 8

Contributions

  • 1. Reconstruct typestate features from standard

type-theoretic programming language primitives. We focus on the following set of typestate features: a) state abstraction, hiding an object representation while expressing the type of the state; b) state “dimensions”, enabling multiple orthogonal typestates over the same object; c) “dynamic state tests”, allowing a case analysis over the abstract state.

  • 2. We show how to idiomatically support both state-based

(typestate) and transition-based (behavioral types) specifications of abstract state evolution.

6

slide-9
SLIDE 9

Language

  • Polymorphic λ-calculus with mutable references

(and immutable records, tagged sums, ...).

  • Technically, we use a variant of L3 adapted for

usability (by simplifying the handling of capabilities,

adding support for sum types, universal/existential type quantification, alternatives, labeled records, ...).

7

Ahmed, Fluet, and Morrisett. L3: A linear language with

  • locations. Fundam. Inform. 2007.
slide-10
SLIDE 10

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

slide-11
SLIDE 11

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

slide-12
SLIDE 12

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

type of contents of cell

slide-13
SLIDE 13

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

type of contents of cell

becomes

ref p rw p A

slide-14
SLIDE 14

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

type of contents of cell

becomes

ref p rw p A

location p links ref to read+write capability that tracks the contents of that cell

slide-15
SLIDE 15

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

type of contents of cell

becomes

ref p rw p A

location p links ref to read+write capability that tracks the contents of that cell

type of contents of cell p (linear - cannot be duplicated)

slide-16
SLIDE 16

Language

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.

8

ref A

type of contents of cell

becomes

ref p rw p A

location p links ref to read+write capability that tracks the contents of that cell

can be freely copied (pure) type of contents of cell p (linear - cannot be duplicated)

slide-17
SLIDE 17

Language

9

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-18
SLIDE 18

Language

9

x : ref p y : ref p z : ref q

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-19
SLIDE 19

Language

9

x : ref p y : ref p z : ref q rw p A rw q B

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-20
SLIDE 20

Language

9

!x

(“de-reference x”)

x : ref p y : ref p z : ref q rw p A rw q B

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-21
SLIDE 21

Language

9

!x

(“de-reference x”)

x : ref p y : ref p z : ref q rw p A rw q B

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-22
SLIDE 22

Language

9

!x

(“de-reference x”)

x : ref p y : ref p z : ref q rw p A rw q B

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-23
SLIDE 23

Language

9

!x

(“de-reference x”)

A x : ref p y : ref p z : ref q rw p A rw q B

  • Mutable state handled as a linear resource:
  • split in pure references and linear capabilities.
  • use location-dependent types to link both.
slide-24
SLIDE 24

Language

10

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-25
SLIDE 25

Language

10

Lexical Typing Environment

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-26
SLIDE 26

Language

10

Lexical Typing Environment Initial Linear Typing Environment

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-27
SLIDE 27

Language

10

Lexical Typing Environment Initial Linear Typing Environment Type of Expression

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-28
SLIDE 28

Language

10

Lexical Typing Environment Initial Linear Typing Environment Type of Expression Resulting Effects

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-29
SLIDE 29

Language

11

resources are either consumed

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-30
SLIDE 30

Language

11

resources are either consumed

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-31
SLIDE 31

Language

12

  • r, threaded

through

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-32
SLIDE 32

Language

12

  • r, threaded

through

  • Capabilities are (linear) typing artifacts (not values)

that are threaded and stacked implicitly.

  • For that, we use a Type-and-Effect system.
  • Typing judgement format:
slide-33
SLIDE 33

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-34
SLIDE 34

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-35
SLIDE 35

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-36
SLIDE 36

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-37
SLIDE 37

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-38
SLIDE 38

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-39
SLIDE 39

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-40
SLIDE 40

Language

13

  • Capabilities can be stacked and unstacked on top of

some type, allowing them to accompany that type.

slide-41
SLIDE 41

14

Types

slide-42
SLIDE 42

15

Syntax

slide-43
SLIDE 43

15

let-expanded

Syntax

slide-44
SLIDE 44

15

let-expanded

Syntax

slide-45
SLIDE 45

Pair Example

16

  • Function that creates stateful Pair objects.
  • The Pair’s components (left and right) are private,

not accessible to clients.

  • The state of Pair is changed indirectly by calling

functions contained in a labeled record (which are technically closures).

slide-46
SLIDE 46

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

17

slide-47
SLIDE 47

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

18

slide-48
SLIDE 48

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

18

slide-49
SLIDE 49

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

18

Γ = pl : loc, l : ref pl Δ = rw pl []

slide-50
SLIDE 50

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

19

Γ = pl : loc, l : ref pl, pr : loc, r : ref pr Δ = rw pl [], rw pr []

slide-51
SLIDE 51

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

20

Γ = pl : loc, l : ref pl, pr : loc, r : ref pr Δ = rw pl [], rw pr []

slide-52
SLIDE 52

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

21

slide-53
SLIDE 53

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

22

slide-54
SLIDE 54

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

22

Δ = rw pl []

slide-55
SLIDE 55

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

23

Δ = rw pl int

slide-56
SLIDE 56

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

24

!( ( int :: rw pl [] ) ⊸ ( [] :: rw pl int ) )

slide-57
SLIDE 57

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

24

!( ( int :: rw pl [] ) ⊸ ( [] :: rw pl int ) )

slide-58
SLIDE 58

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

25

[ initL : !( ( int :: rw pl [] ) ⊸ ( [] :: rw pl int ) ), initR : !( ( int :: rw pr [] ) ⊸ ( [] :: rw pr int ) ), sum : !( ( [] :: rw pl int * rw pr int ) ⊸ ( int :: rw pl int * rw pr int ) ), destroy : !( ( [] :: rw pl int * rw pr int ) ⊸ [] ) ]

slide-59
SLIDE 59

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

25

[ initL : !( ( int :: rw pl [] ) ⊸ ( [] :: rw pl int ) ), initR : !( ( int :: rw pr [] ) ⊸ ( [] :: rw pr int ) ), sum : !( ( [] :: rw pl int * rw pr int ) ⊸ ( int :: rw pl int * rw pr int ) ), destroy : !( ( [] :: rw pl int * rw pr int ) ⊸ [] ) ]

Δ = rw pl [], rw pr []

slide-60
SLIDE 60

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r } end end

26

[ initL : !( ( int :: rw pl [] ) ⊸ ( [] :: rw pl int ) ), initR : !( ( int :: rw pr [] ) ⊸ ( [] :: rw pr int ) ), sum : !( ( [] :: rw pl int * rw pr int ) ⊸ ( int :: rw pl int * rw pr int ) ), destroy : !( ( [] :: rw pl int * rw pr int ) ⊸ [] ) ] :: ( rw pl [] * rw pr [] )

slide-61
SLIDE 61

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

<pl, <pr,{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r }> > end end

27

∃ll.∃lr.( [ initL : !( ( int :: rw ll [] ) ⊸ ( [] :: rw ll int ) ), initR : !( ( int :: rw lr [] ) ⊸ ( [] :: rw lr int ) ), sum : !( ( [] :: rw ll int * rw lr int ) ⊸ ( int :: rw ll int * rw lr int ) ), destroy : !( ( [] :: rw ll int * rw lr int ) ⊸ [] ) ] :: ( rw ll [] * rw lr [] ) )

slide-62
SLIDE 62

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

<pl, <pr,{ initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r }> > end end

27

∃ll.∃lr.( [ initL : !( ( int :: rw ll [] ) ⊸ ( [] :: rw ll int ) ), initR : !( ( int :: rw lr [] ) ⊸ ( [] :: rw lr int ) ), sum : !( ( [] :: rw ll int * rw lr int ) ⊸ ( int :: rw ll int * rw lr int ) ), destroy : !( ( [] :: rw ll int * rw lr int ) ⊸ [] ) ] :: ( rw ll [] * rw lr [] ) )

The object’s representation is exposed!

slide-63
SLIDE 63

let newPair = fun( _ : [] ).

  • pen <pl,l> = new {} in
  • pen <pr,r> = new {} in

< rw pl [], < rw pl int, < rw pr [], < rw pr int { initL = fun( i : int :: rw pl [] ). l := i, initR = fun( i : int :: rw pr [] ). r := i, sum = fun( _ : [] :: rw pl int * rw pr int ). !l+!r, destroy = fun( _ : [] :: rw pl int * rw pr int ). delete l; delete r }> > > > end end

28

∃EL.∃L.∃ER.∃R.( [ initL : !( int :: EL ⊸ [] :: L ), initR : !( int :: ER ⊸ [] :: R ), sum : !( [] :: L * R ⊸ int :: L * R ), destroy : !( [] :: L * R ⊸ [] ) ] :: EL * ER )

slide-64
SLIDE 64

Pair Typestate

29

newPair : !( [] ⊸ ∃EL.∃L.∃ER.∃R.([ initL : !( int :: EL ⊸ [] :: L ), initR : !( int :: ER ⊸ [] :: R ), sum : !( [] :: L * R ⊸ int :: L * R ), destroy : !( [] :: L * R ⊸ [] ) ] :: EL * ER ) )

  • Type expresses the changing properties of the object’s state,

typestate (EmptyLeft, Left, EmptyRight and Right).

  • Orthogonal typestates, “state dimensions” (EL/L and ER/R),

correlate to separate internal state that operates independently.

slide-65
SLIDE 65

Stack Typestate

30

  • Type of a function (polymorphic in the contents to

be stored in the stack) that creates stack objects.

  • Each stack has two states: Empty and NonEmpty.
  • Imprecision in the exact state of the stack is typed

with E⨁NE (alternative): we either have the E typestate or NE the typestate.

slide-66
SLIDE 66

Stack Typestate

30

  • Type of a function (polymorphic in the contents to

be stored in the stack) that creates stack objects.

  • Each stack has two states: Empty and NonEmpty.
  • Imprecision in the exact state of the stack is typed

with E⨁NE (alternative): we either have the E typestate or NE the typestate.

Typestates do not exist at runtime. How can client code distinguish between different states without breaking the abstraction?

slide-67
SLIDE 67

newStack : ∀T.( [] ⊸ ∃E.∃NE.[ push : T :: E⨁NE ⊸ [] :: NE, pop : [] :: NE ⊸ T :: E⨁NE, isEmpty : [] :: E⨁NE ⊸ Empty#([]::E) + NonEmpty#([]::NE), del : [] :: E ⊸ [] ] :: E )

31

Note: !‘s omitted from the type for brevity.

slide-68
SLIDE 68

newStack : ∀T.( [] ⊸ ∃E.∃NE.[ push : T :: E⨁NE ⊸ [] :: NE, pop : [] :: NE ⊸ T :: E⨁NE, isEmpty : [] :: E⨁NE ⊸ Empty#([]::E) + NonEmpty#([]::NE), del : [] :: E ⊸ [] ] :: E )

32

Note: !‘s omitted from the type for brevity.

slide-69
SLIDE 69

newStack : ∀T.( [] ⊸ ∃E.∃NE.[ push : T :: E⨁NE ⊸ [] :: NE, pop : [] :: NE ⊸ T :: E⨁NE, isEmpty : [] :: E⨁NE ⊸ Empty#([]::E) + NonEmpty#([]::NE), del : [] :: E ⊸ [] ] :: E )

32

Note: !‘s omitted from the type for brevity.

Clients can use case analysis to determine precisely in which state the stack is at, “dynamic state test”, anchoring values to the abstract stack states.

slide-70
SLIDE 70

Contributions

  • 1. Reconstruct typestate features from standard

type-theoretic programming language primitives. We focus on the following set of typestate features: a) state abstraction, hiding an object representation while expressing the type of the state; b) state “dimensions”, enabling multiple orthogonal typestates over the same object; c) “dynamic state tests”, allowing a case analysis over the abstract state.

  • 2. We show how to idiomatically support both state-based

(typestate) and transition-based (behavioral types) specifications of abstract state evolution.

33

slide-71
SLIDE 71

Back to Pair...

34

The evolution of the abstract state can be specified using a state-machine/automaton/protocol.

EL L

initL

ER R

initR sum destroy

L R

none

* *

slide-72
SLIDE 72

Back to Pair...

35

EL L

initL

ER R

initR sum destroy

L R

none

Typestates focus on the states that model the abstracted changes of the mutable state. The evolution of the abstract state can be specified using a state-machine/automaton/protocol.

* *

slide-73
SLIDE 73

Back to Pair...

36

EL L

initL

ER R

initR sum destroy

L R

none

Behavioral Types focus on the transitions (“behavior”) keeping the states anonymous.

* *

The evolution of the abstract state can be specified using a state-machine/automaton/protocol.

slide-74
SLIDE 74

Abstracting and Hiding State

37

  • In our system, the notion of typestates is related

to state abstraction, while the notion of behavior is related to hiding state.

  • With typestates, states are named which can be

convenient when there are multiple paths through the protocol.

  • With behavioral types, states are implicit which

simplifies descriptions of linear usages and makes it easier to provide structural equivalences.

Caires and Seco. The type discipline of behavioral separation. POPL 2013.

slide-75
SLIDE 75

38

  • We have already seen how to model typestates

through standard existential abstraction.

  • Interestingly, the notion of “behavior” can be

modeled with what was already shown!

  • However, it requires using an idiom to capture the

typestate inside a function effectively hiding it.

Abstracting and Hiding State

slide-76
SLIDE 76

39

  • A typestate can be borrowed by a function if that

function requires the typestate as an argument but the function returns the typestate as a result.

Borrowing and Capturing

initL : !( int :: EL ⊸ [] :: L )

slide-77
SLIDE 77

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

slide-78
SLIDE 78

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x)

slide-79
SLIDE 79

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x) Γ = initL : !( int :: EL ⊸ [] :: L )

slide-80
SLIDE 80

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x) Δ = EL Γ = initL : !( int :: EL ⊸ [] :: L )

slide-81
SLIDE 81

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x) Δ = EL Γ = initL : !( int :: EL ⊸ [] :: L )

slide-82
SLIDE 82

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x) Δ = EL Δ = . Γ = initL : !( int :: EL ⊸ [] :: L )

slide-83
SLIDE 83

40

  • Alternatively, a function may depend on state that

was captured from the enclosing linear environment (similar to a closure, but with state).

Borrowing and Capturing

fun( x : int ).(initL x) Δ = EL Δ = . int ⊸ [] :: L Γ = initL : !( int :: EL ⊸ [] :: L )

slide-84
SLIDE 84

Hiding (Type)state

41

  • Capturing the typestate enables us to hide the

typestate needed by the function’s argument.

  • Hiding the typestate from the result is not

immediately possible. However, we can define a complete sequence of uses (“behavior”) that ends in a function that destroys the (type)state.

  • One possible linear “behavior” for the Pair is:

EL L

initL

ER R

initR sum destroy none

EL R L R

slide-85
SLIDE 85

Hiding (Type)state

42

  • Capturing the typestate enables us to hide the

typestate needed by the function’s argument.

  • Hiding the typestate from the result is not

immediately possible. However, we can define a complete sequence of uses (“behavior”) that ends in a function that destroys the (type)state.

  • One possible linear “behavior” for the Pair is:

EL L

initL

ER R

initR sum destroy none

EL R L R

slide-86
SLIDE 86

43

fun( a : int ). { initR(a) , fun( b : int ).

  • {
  • initL(b)

,

  • fun( _ : [] ).
  • {

sum(_) , fun( _ : [] ).destroy(_) } } }

slide-87
SLIDE 87

44

fun( a : int ). { initR(a) , fun( b : int ).

  • {
  • initL(b)

,

  • fun( _ : [] ).
  • {

sum(_) , fun( _ : [] ).destroy(_) } } } [] :: L * R ⊸ [] [] ⊸ []

slide-88
SLIDE 88

45

fun( a : int ). { initR(a) , fun( b : int ).

  • {
  • initL(b)

,

  • fun( _ : [] ).
  • {

sum(_) , fun( _ : [] ).destroy(_) } } } [] :: L * R ⊸ [] [] ⊸ [] [] :: L * R ⊸ int :: L * R

slide-89
SLIDE 89

46

fun( a : int ). { initR(a) , fun( b : int ).

  • {
  • initL(b)

,

  • fun( _ : [] ).
  • {

sum(_) , fun( _ : [] ).destroy(_) } } } [] :: L * R ⊸ [] [] :: L * R ⊸ int :: L * R int :: EL ⊸ [] :: L int :: ER ⊸ [] :: R [] ⊸ []

slide-90
SLIDE 90

46

fun( a : int ). { initR(a) , fun( b : int ).

  • {
  • initL(b)

,

  • fun( _ : [] ).
  • {

sum(_) , fun( _ : [] ).destroy(_) } } } [] :: L * R ⊸ [] [] :: L * R ⊸ int :: L * R int :: EL ⊸ [] :: L int :: ER ⊸ [] :: R [] ⊸ [] Δ = EL, ER

slide-91
SLIDE 91

47

slide-92
SLIDE 92

47

Clients never see the underlying typestates. They

  • nly see the usage requirement (“behavior”).
slide-93
SLIDE 93

Technical Results

48

slide-94
SLIDE 94

Related Work

DeLine and Fähndrich. Typestates for objects. ECOOP 2004. DeLine and Fähndrich. Enforcing high-level protocols in low-level

  • software. PLDI 2001.

Bierhoff and Aldrich. Modular typestate checking of aliased objects. OOPSLA 2007. Beckman, Bierhoff, and Aldrich. Verifying correct usage of atomic blocks and typestate. OOPSLA 2008. Sunshine, Naden, Stork, Aldrich, and Tanter. First-class state change in Plaid. OOPSLA 2011.

49

  • They support many advanced uses (method dispatch, inheritance,

sharing mechanisms, concurrency, etc).

  • We focus on reconstructing a smaller set of typestate features

from type-theoretic primitives (separation and linear logic). Which enables combining abstracting and hiding state.

slide-95
SLIDE 95

Related Work

Ahmed, Fluet, and Morrisett. L3: A linear language with locations. Fundam.

  • Inform. 2007.

Walker and Morrisett. Alias types for recursive data structures. TIC 2001. Smith, Walker, and Morrisett. Alias types. ESOP 2000. Parkinson and Bierman. Separation logic and abstraction. POPL 2005.

50

Paper includes additional Related Work.

  • Abstract predicates can represent a richer domain of abstract state

(not limited to a finite number, can be parametric, etc).

  • Typestates encode a simpler notion of abstraction, generally

targets a more lightweight verification.

  • We extend their work with usability related changes (implicitly

threaded capabilities, alternatives, etc).

slide-96
SLIDE 96

Summary

  • 1. Encoding typestates using existential types in a

substructural type-and-effect system.

  • 2. Support both state-based and transition-based

specifications of abstract state evolution.

  • Experimental Prototype Implementation:

https://code.google.com/p/dead-parrot

  • Future

Work: Sharing of resources through disconnected variables.

51

slide-97
SLIDE 97

Prototype

JavaScript-based implementation, runs in browser.

52

slide-98
SLIDE 98

Summary

  • 1. Encoding typestates using existential types in a

substructural type-and-effect system.

  • 2. Support both state-based and transition-based

specifications of abstract state evolution.

  • Experimental Prototype Implementation:

https://code.google.com/p/dead-parrot

  • Future

Work: Sharing of resources through disconnected variables.

53