The design of Mezzo Franois Pottier Jonathan Protzenko INRIA CMU, - - PowerPoint PPT Presentation

the design of mezzo
SMART_READER_LITE
LIVE PREVIEW

The design of Mezzo Franois Pottier Jonathan Protzenko INRIA CMU, - - PowerPoint PPT Presentation

The design of Mezzo Franois Pottier Jonathan Protzenko INRIA CMU, Sep 2013 1 / 51 Outline Motivation Design principles Algebraic data structures Extra examples Aliasing Project status 2 / 51 Premise The types of OCaml, Haskell,


slide-1
SLIDE 1

The design of Mezzo

François Pottier Jonathan Protzenko

INRIA

CMU, Sep 2013

1 / 51

slide-2
SLIDE 2

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

2 / 51

slide-3
SLIDE 3

Premise

The types of OCaml, Haskell, Java, C#, etc.:

  • describe the structure of data,
  • but do not distinguish trees and graphs,
  • and do not control who has permission to read or write.

3 / 51

slide-4
SLIDE 4

Question

Could a more ambitious static discipline:

  • rule out more programming errors,
  • and enable new programming idioms,
  • while remaining reasonably simple and flexible?

4 / 51

slide-5
SLIDE 5

Goals

We would like to rule out:

  • representation exposure;
  • data races;
  • violations of object protocols;

and to enable:

  • gradual initialization;
  • type changes along with state changes;
  • (in certain cases) explicit memory re-use.

5 / 51

slide-6
SLIDE 6

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

6 / 51

slide-7
SLIDE 7

Principle 1. Nothing is fixed

A variable x does not have a fixed type throughout its lifetime. Instead,

  • at each program point in the scope of x,
  • one may have zero, one, or more (static) permissions to use x

in certain ways.

7 / 51

slide-8
SLIDE 8

Layout and ownership go hand in hand

As a consequence, permissions describe layout and ownership. A permission of the form “x @ t” allows using x at type t. It describes the shape and extent of a heap fragment, rooted at x, and describes certain access rights for this memory. In short, “to know about x” is “to have access to x” is “to own x”.

8 / 51

slide-9
SLIDE 9

Principle 2. Just two access modes

The system imposes a global invariant: at any time,

  • if x is a mutable object, there exists at most one permission to

access it (for reading and writing);

  • if x is an immutable object, there may exist arbitrarily many

permissions to access it (for reading). No counting. No fractions.

9 / 51

slide-10
SLIDE 10

Some syntax and examples

For instance,

  • “x @ list int” provides (read) access to an immutable list of

integers, rooted at x.

  • “x @ mlist int” provides (exclusive, read/write) access to a

mutable list of integers at x.

  • “x @ list (ref int)” offers read access to the spine and

read/write access to the elements, which are integer cells.

10 / 51

slide-11
SLIDE 11

Principle 3. Any (known) alias is as good as any other

An equality “x = y” is a permission, sugar for “x @ (=y)”. In its presence, “x @ t” can be turned into “y @ t”, and vice-versa. No “borrowing”.

11 / 51

slide-12
SLIDE 12

Control of duplication

A value can be copied (always). Can a permission be copied?

  • “x @ list int” can be copied: read access can be shared.
  • “x = y” can be copied: equalities are forever.
  • “x @ mlist int” and “x @ list (ref int)” must not be

copied, as they imply exclusive access to part of the heap. One can always tell whether a permission is duplicable or affine.

12 / 51

slide-13
SLIDE 13

Control of aliasing: the bad

let x = 0 in let y = ref x in let z = (y, y) in ...

We have “x @ int” and “y @ ref (=x)” and “z @ (=y, =y)”. Thus, we have “x @ int” and “y @ ref int” and “z @ (=y, =y)”. We cannot deduce “z @ (ref int, ref int)”, as this reasoning step would require duplicating “y @ ref int”. Aliasing of mutable data is restricted.

13 / 51

slide-14
SLIDE 14

Control of aliasing: the good

let z : (ref int, ref int) = ... in let (x, y) = z in ...

We have “z @ (ref int, ref int)” and “z @ (=x, =y)”. I.e., “z @ (=x, =y)” and “x @ ref int” and “y @ ref int”. We have an exclusive access token for each of x and y. There follows that these addresses must be distinct. Technically, the word “and” above is a conjunction * that requires separation at mutable data and agreement at immutable data.

14 / 51

slide-15
SLIDE 15

Summary so far: the good

Why is this a useful discipline? The uniqueness of read/write permissions:

  • rules out representation exposure and data races;
  • allows the type of an object to vary with time.

15 / 51

slide-16
SLIDE 16

Summary so far: the bad

Isn't this a restrictive discipline? Yes, it is. In our defense,

  • there is no restriction on the use of immutable data;
  • there is an escape hatch that involves dynamic checks.

16 / 51

slide-17
SLIDE 17

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

17 / 51

slide-18
SLIDE 18

Immutable lists

The algebraic data type of immutable lists is defined as in ML:

data list a = | Nil | Cons { head: a; tail: list a }

18 / 51

slide-19
SLIDE 19

Mutable lists

To define a type of mutable lists, one adds a keyword:

data mutable mlist a = | MNil | MCons { head: a; tail: mlist a }

19 / 51

slide-20
SLIDE 20

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

......

20 / 51

slide-21
SLIDE 21

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

. xs @ mlist a .....

20 / 51

slide-22
SLIDE 22

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

.. . xs @ MNil ....

20 / 51

slide-23
SLIDE 23

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

... . xs @ MCons { head: a; tail: mlist a } ...

20 / 51

slide-24
SLIDE 24

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

.... . xs @ MCons { head: (=h); tail: (=t) } * h @ a * t @ mlist a ..

20 / 51

slide-25
SLIDE 25

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

..... . xs @ MCons { head = h; tail = t } * h @ a * t @ mlist a .

20 / 51

slide-26
SLIDE 26

Permission analysis & refinement

.

match xs with | MNil ->

.

... | MCons ->

.

let x = xs.head in

.

... end

...... . xs @ MCons { head = h; tail = t } * h @ a * t @ mlist a * x = h

20 / 51

slide-27
SLIDE 27

Principles

This illustrates two mechanisms:

  • A nominal permission can be unfolded and refined to a

structural one.

  • A structural permission can be decomposed into a

conjunction of permissions for the fields. These reasoning steps are reversible. This means that “xs @ list (ref a)” denotes a list of pairwise distinct references.

21 / 51

slide-28
SLIDE 28

A recursive function

val length: [a] mlist a -> int

This type should be understood as follows:

  • length requires one argument xs, along with the static

permission “xs @ mlist a”.

  • length returns one result n, along with the static permission

“xs @ mlist a * n @ int”. By convention, the permissions demanded by a function are also returned, unless the “consumes” keyword is used.

22 / 51

slide-29
SLIDE 29

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

........

23 / 51

slide-30
SLIDE 30

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

. . xs @ mlist a .......

23 / 51

slide-31
SLIDE 31

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

.. . xs @ MNil ......

23 / 51

slide-32
SLIDE 32

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

... . xs @ MNil .....

23 / 51

slide-33
SLIDE 33

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

.... . xs @ mlist a ....

23 / 51

slide-34
SLIDE 34

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

..... . xs @ MCons { head = h; tail = t } h @ a t @ mlist a ...

23 / 51

slide-35
SLIDE 35

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

...... . xs @ MCons { head = h; tail = t } h @ a t @ mlist a ..

23 / 51

slide-36
SLIDE 36

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

....... . xs @ MCons { head: a; tail: mlist a } .

23 / 51

slide-37
SLIDE 37

A recursive function

val rec length_aux [a] (accu: int, xs: mlist a) : int = match xs with . | MNil -> . accu . | MCons -> . length_aux (accu + 1, xs.tail) .

.

end val length [a] (xs: mlist a) : int = length_aux (0, xs)

........ . xs @ mlist a

23 / 51

slide-38
SLIDE 38

Tail recursion versus iteration

The analysis of this code is surprisingly simple.

  • This is a tail-recursive function, i.e.,

a loop in disguise.

  • As we go, there is a list ahead of us and

a list segment behind us.

  • Ownership of the latter is implicit, i.e.,

framed out. Recursive reasoning, iterative execution.

24 / 51

slide-39
SLIDE 39

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

25 / 51

slide-40
SLIDE 40

What's here

A couple more examples:

  • melding mutable lists;
  • concatenating immutable lists.

Both feature iteration as tail recursion. The latter also demonstrates gradual initialization.

26 / 51

slide-41
SLIDE 41

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

.......

27 / 51

slide-42
SLIDE 42

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

.

not consumed!

......

27 / 51

slide-43
SLIDE 43

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

.. .

consumed!

.....

27 / 51

slide-44
SLIDE 44

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

... . xs @ MCons { head: a; tail = t } t @ MNil ys @ mlist a ....

27 / 51

slide-45
SLIDE 45

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

.... . xs @ MCons { head: a; tail = ys } t @ MNil ys @ mlist a ...

27 / 51

slide-46
SLIDE 46

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

..... . xs @ MCons { head: a; tail: mlist a } t @ MNil ..

27 / 51

slide-47
SLIDE 47

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

...... . xs @ MCons { head: a; tail: mlist a } .

27 / 51

slide-48
SLIDE 48

Melding mutable lists (1/2)

val rec meld_aux [a] (xs: MCons { head: a; tail: mlist a }, .

.

consumes ys: mlist a . ) : () = match xs.tail with | MNil

  • > .

xs.tail <- ys . | MCons -> meld_aux (xs.tail, ys) . end

....... . xs @ MCons { head: a; tail = t }

is framed out during the call

27 / 51

slide-49
SLIDE 49

Melding mutable lists (2/2)

val meld [a] (consumes xs: mlist a, consumes ys: mlist a) : mlist a = match xs with | MNil

  • > ys

| MCons -> meld_aux (xs, ys); xs end

28 / 51

slide-50
SLIDE 50

Concatenating immutable lists

. .

Cons

.

head

.

tail

.

MCons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

xs

.

ys

29 / 51

slide-51
SLIDE 51

Concatenating immutable lists

. .

Cons

.

head

.

tail

.

MCons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

xs

.

ys

29 / 51

slide-52
SLIDE 52

Concatenating immutable lists

. .

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

Cons

.

head

.

tail

.

xs

.

ys

29 / 51

slide-53
SLIDE 53

Concatenating immutable lists (1/3)

We define a type for a partially-initialized “cons” cell:

alias mcons a = MCons { head: a; tail: () }

The permission “c @ mcons a” allows updating c.tail. It also allows freezing the cell c.

30 / 51

slide-54
SLIDE 54

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

......

31 / 51

slide-55
SLIDE 55

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

. .

all three inputs consumed!

.....

31 / 51

slide-56
SLIDE 56

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

.. .

upon return, dst is a list

....

31 / 51

slide-57
SLIDE 57

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

... . dst.tail is initialized ...

31 / 51

slide-58
SLIDE 58

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

.... . dst becomes an immutable block ..

31 / 51

slide-59
SLIDE 59

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

..... . dst' becomes a valid list .

31 / 51

slide-60
SLIDE 60

Concatenating immutable lists (2/3)

val rec append_aux [a] (consumes .( dst: mcons a, xs: list a, ys: list a)) : (| dst @ list a) .= match xs with | Cons -> let dst' = MCons { head = xs.head; tail = () } in dst.tail <- dst'; . tag of dst <- Cons; . append_aux (dst', xs.tail, ys) .

.

| Nil -> dst.tail <- ys; tag of dst <- Cons end

...... .

hence, dst too becomes a valid list

31 / 51

slide-61
SLIDE 61

Concatenating immutable lists (3/3)

val append [a] (consumes (xs: list a, ys: list a)) : list a = match xs with | Cons -> let dst = MCons { head = xs.head; tail = () } in append_aux (dst, xs.tail, ys); dst | Nil -> ys end

32 / 51

slide-62
SLIDE 62

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

33 / 51

slide-63
SLIDE 63

Aliasing is restricted

By default, mutable data cannot be aliased. Several independent mechanisms circumvent this restriction:

  • locks in the style of concurrent separation logic;
  • adoption and abandon, an original feature;
  • nesting in the style of Boyland.

The first two are more flexible, but are runtime mechanisms and can cause deadlocks and runtime errors.

34 / 51

slide-64
SLIDE 64

Locks (1/2)

We need two types:

abstract lock (p: perm) fact duplicable (lock p) abstract locked

35 / 51

slide-65
SLIDE 65

Locks (2/2)

The basic operations are:

val new: [p: perm] (| consumes p)

  • > lock p

val acquire: [p: perm] (l: lock p)

  • > (| p * l @ locked)

val release: [p: perm] (l: lock p | consumes (p * l @ locked)) -> ()

“try acquire” can also be expressed.

36 / 51

slide-66
SLIDE 66

Locks are safe

In the presence of threads & locks,

  • well-typed programs do not go wrong...
  • ...and are data-race-free (Thibaut Balabonski, F.P.).

The type system does not prevent deadlocks.

37 / 51

slide-67
SLIDE 67

Benefits of locks

Although “x @ a” cannot be shared, “l @ lock (x @ a)” can. A value x, without any permission, can be shared too. Thus, an object that is protected by a lock can be shared:

alias protected a = (x: unknown, lock (x @ a))

This allows an encoding of ML into Mezzo, of theoretical interest

  • nly, where every mutable object is protected by a lock.

38 / 51

slide-68
SLIDE 68

Hiding

Hiding a function's internal state allows sharing this function:

val hide : [a, b, s : perm] ( f : (a | s) -> b | consumes s ) -> (a -> b)

39 / 51

slide-69
SLIDE 69

Hiding

Hiding a function's internal state allows sharing this function:

val hide [a, b, s : perm] ( f : (a | s) -> b | consumes s ) : (a -> b) = let l : lock s = new () in . fun (x : a) : b = . acquire l; . let y = f x in release l; y

...

40 / 51

slide-70
SLIDE 70

Hiding

Hiding a function's internal state allows sharing this function:

val hide [a, b, s : perm] ( f : (a | s) -> b | consumes s ) : (a -> b) = let l : lock s = new () in . fun (x : a) : b = . acquire l; . let y = f x in release l; y

. . l @ lock s ..

40 / 51

slide-71
SLIDE 71

Hiding

Hiding a function's internal state allows sharing this function:

val hide [a, b, s : perm] ( f : (a | s) -> b | consumes s ) : (a -> b) = let l : lock s = new () in . fun (x : a) : b = . acquire l; . let y = f x in release l; y

.. . l @ lock s .

40 / 51

slide-72
SLIDE 72

Hiding

Hiding a function's internal state allows sharing this function:

val hide [a, b, s : perm] ( f : (a | s) -> b | consumes s ) : (a -> b) = let l : lock s = new () in . fun (x : a) : b = . acquire l; . let y = f x in release l; y

... . l @ locked s

40 / 51

slide-73
SLIDE 73

Adoption and abandon

Adoption and abandon, also known as give & take, allow a single static permission to control a group of (mutable) objects. The objects in the group can be aliased in arbitrary ways.

41 / 51

slide-74
SLIDE 74

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-75
SLIDE 75

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-76
SLIDE 76

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-77
SLIDE 77

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-78
SLIDE 78

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-79
SLIDE 79

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-80
SLIDE 80

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-81
SLIDE 81

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. Uniqueness is guaranteed via a runtime check.

42 / 51

slide-82
SLIDE 82

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. . Uniqueness is guaranteed via a runtime check.

42 / 51

slide-83
SLIDE 83

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. . Uniqueness is guaranteed via a runtime check.

42 / 51

slide-84
SLIDE 84

give & take: overview

. .

x @ node

.

x @ dynamic

. give x to y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ dynamic

. c .

  • .

p . y .

x @ node

. take x from y .

x @ node

.

?

. . Uniqueness is guaranteed via a runtime check.

42 / 51

slide-85
SLIDE 85

give & take: dynamic semantics

Mutable objects can serve as adopters or adoptees. Every object maintains a (possibly null) pointer to its adopter. “give x to y” sets this field; “take x from y” tests it and clears it. “take” can fail.

43 / 51

slide-86
SLIDE 86

give & take: static semantics

“give x to y” and “take x from y” need exclusive ownership of y. “give x to y” consumes “x @ u”, while “take x from y” produces “x @ u”, where the type u of the adoptee is determined by the type

  • f the adopter.

Owning an object implicitly means owning all of its adoptees too.

44 / 51

slide-87
SLIDE 87

give & take: bottom line

Well-typed programs do not go wrong, but can fail at “take”. This is a dynamic version of F¨ ahndrich and DeLine's regions with adoption & focus. The ownership hierarchy is partly static, partly dynamic.

45 / 51

slide-88
SLIDE 88

Outline

Motivation Design principles Algebraic data structures Extra examples Aliasing Project status

46 / 51

slide-89
SLIDE 89

Who we are

The project was launched in late 2011 and currently involves

  • Jonathan Protzenko (Ph.D student, soon to graduate),
  • Thibaut Balabonski (post-doc researcher),
  • and myself (INRIA researcher).

47 / 51

slide-90
SLIDE 90

Where we are

We currently have:

  • a formal definition and type soundness proof for Core Mezzo,

including give & take and threads & locks;

  • a prototype type-checker.

48 / 51

slide-91
SLIDE 91

What next?

In the short term, we would like to:

  • put more work into type inference, which is tricky;
  • experimentally evaluate Mez

zo's expressiveness and usability;

  • compile Mezzo down to untyped OCaml, or some other target.

49 / 51

slide-92
SLIDE 92

What next?

Many as-yet-unanswered questions!

  • Is this a good mix between static and dynamic mechanisms?
  • Can we write modular code?
  • Can we express object protocols?
  • What about specifications & proofs of programs?

50 / 51

slide-93
SLIDE 93

Thank you

More information is online at

http://gallium.inria.fr/~protzenk/mezzo-lang/

51 / 51