Practical Affine Types and Typestate-Oriented...

22
Practical Ane Types and Typestate-Oriented Programming 1 Philipp Haller Dagstuhl Seminar 17051 Theory and Applications of Behavioural Types Schloss Dagstuhl, Germany January 30 th , 2017 KTH Royal Institute of Technology Stockholm, Sweden

Transcript of Practical Affine Types and Typestate-Oriented...

Page 1: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Practical Affine Types and Typestate-Oriented

Programming

1

Philipp Haller

Dagstuhl Seminar 17051 Theory and Applications of Behavioural Types

Schloss Dagstuhl, Germany January 30th, 2017

KTH Royal Institute of Technology Stockholm, Sweden

Page 2: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Practical Affine Types

• Original motivation: Scala cannot ensure concurrency safety for library-based concurrency abstractions

• Result (OOPSLA ’16):A design for affine types that enables expressing isolation of concurrent processes in a shared mutable heap

• Goal:Generalize type system to typestate system

2

This also applies to Java, C++, and virtually all widely-used

programming languages

Page 3: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Why a New Design for Affine Types?

• A lot of progress on related type systems:linear types, static capabilities, uniqueness types, ownership types, region inference, etc.

• Challenges:

• Sound and robust integration with advanced type system features

• Adoption on large scale

• Key: reuse of existing code

3

Example: local type inference

Page 4: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

A New Design for Affine Types

• Enter LaCasa: Affine types for Scala

• Objects of affine type have unique, statically-tracked owner

• Ownership is transferable

• LaCasa combines two concepts:

• Encapsulated boxes

• Access permissions

4

Page 5: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Boxes and Access Permissions

• Box = polymorphic heap cell with type member C that uniquely identifies permission required for access

• Permission = stack-local value controlling access to uniquely identified box

CanAccess { type C }

Box[T] { type C }

5

Page 6: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Matching Boxes and Permissions

• Type members and path-dependent types match up boxes and permissions

• Example:

def method[T](box: Box[T]) (p: CanAccess { type C = box.C }): Unit

6

Page 7: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Creating Boxes and Permissions

mkBox[Message] { packed =>

}

class Message { var arr: Array[Int] = _ }

sealed trait Packed[+T] { val box: Box[T] val access: CanAccess { type C = box.C } }

val access = packed.access val box = packed.box …

7

LaCasa library

Page 8: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Accessing Boxes• Boxes are encapsulated

• Boxes must be opened for access

mkBox[Message] { packed => val access = packed.access val box = packed.box

box.open({ msg => msg.arr = Array(1, 2, 3, 4) })(access) }

8

Page 9: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Accessing Boxes• Boxes are encapsulated

• Boxes must be opened for access

mkBox[Message] { packed => implicit val access = packed.access val box = packed.box

box open { msg => msg.arr = Array(1, 2, 3, 4) } }

Requires implicit access permission

9Lewis et al. Implicit parameters: dynamic scoping with static types. POPL '00Oliveira et al. The implicit calculus: a new foundation for generic programming. PLDI '12

Page 10: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Consuming PermissionsExample: transfering a box from one actor to another consumes its access permission

mkBox[Message] { packed => implicit val access = packed.access val box = packed.box … someActor.send(box)

// illegal to access `box` here! }

10

How to enforce this?

Page 11: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Permissions and Continuations

• Make implicit permission unavailable in continuation of permission-consuming call

• Scala’s type system is flow-insensitive => use continuation passing

• Restrict continuation to exclude consumed permission

11

Page 12: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Continuation-Passing Style

mkBox[Message] { packed => implicit val access = packed.access val box = packed.box … someActor.send(box) { // make `access` unavailable … } }

12

Page 13: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Restricting Continuations• Continuation disallows capturing variables of

the type of access

• Leverage spores [1]

def send(msg: Box[T]) (cont: NullarySpore[Unit] { type Excluded = CanAccess { type C = msg.C } }) (implicit p: CanAccess { type C = msg.C }): Nothing

13

“May not occur in captured types”

[1] Miller, Haller, and Odersky. Spores: A type-based foundation for closures in the age of concurrency and distribution. ECOOP ’14

CPS enforced via control-flow exceptions (see paper)

Page 14: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Encapsulation

Problem: not all types safe to transfer!

14

class Message { var arr: Array[Int] = _ def leak(): Unit = { SomeObject.fld = arr } }

object SomeObject { var fld: Array[Int] = _ }

Page 15: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Encapsulation• Ensuring absence of data races (“concurrency safety”)

requires restricting types put into boxes

• Insight: leverage object capability discipline [2]:*

• Methods only access parameters and this

• Methods only instantiate object-capability safe classes

• Types of fields are object-capability safe

15* simplified

[2] Mark S. Miller. Robust Composition: Towards a Unified Approach to Access Control and Concurrency Control. PhD thesis, 2006

Page 16: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Object Capabilities in Scala

• How common is object-capability safe code in Scala?

• Empirical study of over 75,000 SLOC of open-source Scala code:

16

Project Version SLOC GitHub statsScala stdlib 2.11.7 33,107 ✭5,795 👥257Signal/Collect 8.0.6 10,159 ✭123 👥11GeoTrellis 0.10.0-RC2 35,351 ✭400 👥38-engine 3,868-raster 22,291-spark 9,192

Page 17: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Object Capabilities in Scala

Results of empirical study:

17

Project #classes/traits #ocap (%) #dir. insec. (%)Scala stdlib 1,505 644 (43%) 212/861 (25%)Signal/Collect 236 159 (67%) 60/77 (78%)GeoTrellis-engine 190 40 (21%) 124/150 (83%)-raster 670 233 (35%) 325/437 (74%)-spark 326 101 (31%) 167/225 (74%)Total 2,927 1,177 (40%) 888/1,750 (51%)

Page 18: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

LaCasa: Summary• Type-based notion of the object capability

discipline is possible and beneficial

• Object capabilities + path-dependent types + stack locality enable affine types

• Code reuse with minimal effort

• Valid components of affine types conform to the object capability discipline

• Binary check whether a class is reusable unchanged

18

Implicit parameters reduce syntactic overhead

Haller and Loiko:LaCasa: Lightweight Affinity and Object Capabilities in Scala. OOPSLA ’16

Code: https://github.com/phaller/lacasa

Page 19: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

In the Paper• Implementation:

• Compiler plugin for Scala 2.11.x and integration with actors

• Enforcement of continuation-passing style

• Formalization: object-oriented core languages

• CLC1: type-based notion of object capabilities

• CLC2: uniqueness via flow-insensitive permissions

• CLC3: concurrent extension

• Soundness proof

• Isolation theorem for processes with shared heap

19

Formal model in Coq

Page 20: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Towards TypestateIdea:

• Refine permission types: typestate as type member

• Change of typestate = permission replacement

20

trait Alive // typestate root

trait CanAccess { type C type State <: Alive }

Page 21: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Example: Iterator

21

def next[T](b: Box[Iterator[T]]) (implicit p: CanAccess { type C = b.C type State = Available }) (cont: Spore[(T, Packed[Iterator[T]]), Unit] { type Excluded = CanAccess { type C = b.C } }): Nothing

Provide access to iterator using fresh permission in

continuation

sealed trait Packed[+T] {

val box: Box[T]

val access: CanAccess {

type C = box.C }

}

Page 22: Practical Affine Types and Typestate-Oriented …materials.dagstuhl.de/files/17/17051/17051.PhilippHaller...Practical Affine Types and Typestate-Oriented Programming 1 Philipp Haller

Conclusion

• LaCasa: Object capabilities + path-dependent types + CPS = lightweight affinity (OOPSLA ’16)

• Hypothesis: LaCasa suitable as basis for typestate system

• Typestates as types

• CPS unwieldy

22

Thank you!