pony vug prime cuts the best pieces of pony

177
Prime Cuts The Best Pieces of Pony Andrew Turley February 2, 2017

Upload: aturleyslides

Post on 13-Apr-2017

217 views

Category:

Software


4 download

TRANSCRIPT

Prime CutsThe Best Pieces of Pony

Andrew TurleyFebruary 2, 2017

About MeName

Andrew Turley

Contact@casio_juarez / [email protected]

Career

Currently at Sendence

What Is Pony?

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

BSD licenseCopyright (c) 2014-2015, Causality Ltd.All rights reserved.

Redistribution and use in source and binary forms, with or withoutmodification, are permitted provided that the following conditions are met:

1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

Classes, Interfaces, Traits(but they may work a little differently than you expect)

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

Actors communicate by passing messages to other

actors

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

The compiler enforces what you can and cannot do with

an object

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

Uses LLVM to compile to native code

What Is Pony?“Pony is an open-source, object-oriented, actor-model, capabilities-secure, high performance programming language.” -- ponylang.org

Also:

● powerful type system (unions, intersections, parameterized types and functions)

● fast actor-based garbage collection system

hello.pony

hello.ponyactor Main new create(env: Env) => env.out.print(“hello world”)

more-interesting.pony

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

traits: nominal subtyping

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

interfaces: structural subtyping

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

primitive: object with no data and only one instance

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

more-interesting.ponytrait Shape fun area(): F64

interface Named fun name(): String

class Circle is Shape let _radius: F64 new create(radius: F64) => _radius = radius fun name(): String => "circle" fun area(): F64 => 3.14159 * _radius * _radius

class Square is Shape let _side: F64 new create(side: F64) => _side = side fun name(): String => "square" fun area(): F64 => _side * _side

primitive AreaReporter fun report(shape: (Shape & Named)): String => "The area of this " + shape.name() + " is " + shape.area().string()

actor Main new create(env: Env) => let s: F64 = 15.3 var area = AreaReporter.report(Circle(s)) env.out.print(area) area = AreaReporter.report(Square(s)) env.out.print(area)

> ./ponyc src/more-interesting> ./more-interestingThe area of this circle is 735.415The area of this square is 234.09>

Pony: The Really Interesting Parts

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee

that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee

that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee

that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee

that a program is data-race-free.

Pony: The Really Interesting PartsPony uses actors and reference capabilities to allow the compiler to guarantee that a program is

data-race-free.

Pony: The Really Interesting Parts

data-race-free(this is the part you should remember)

Off To The Data Races!

Off To The Data Races!Some pseudo code (not Pony) …

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { inc() print(“a = “ + a)}

1000000

Off To The Data Races!Some more pseudo code (not Pony) …

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

● Run “inc()” simultaneously in two places

● wait for both runs to finish● print the value of “a”

Off To The Data Races!Some more pseudo code (not Pony) …

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

Expected (two threads each

incrementing a variable

1000000 times):

2000000

Off To The Data Races!Some more pseudo code (not Pony) …

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

Expected:

2000000

Actual Run 1:

1987735

Actual Run 2:

1935010

Actual Run 3:

1941217

Off To The Data Races!Some more pseudo code (not Pony) …

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

Expected:

2000000

Actual Run 1:

1987735

Actual Run 2:

1935010

Actual Run 3:

1941217

WHY?

Off To The Data Races!In thread1 …

// get the value of “a”// add 1 to that value// write the new value back to “a”a = a + 1

Meanwhile, in thread2...

// get the value of “a”// add 1 to that value// write the new value back to “a”a = a + 1

a = 26

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value// write the new value back to “a”a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value// write the new value back to “a”a = a + 1

a = 26

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a”a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a”a = a + 1

a = 26

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

a = 27

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

a = 27

We wanted a = 28

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

a = 27

This may not happen every time, but each time it happens it increases the error of the result.

We wanted a = 28

Off To The Data Races!In thread1 …

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

Meanwhile, in thread2...

// get the value of “a” 26// add 1 to that value 26 + 1 = 27// write the new value back to “a” a = 27a = a + 1

a = 27

This may not happen every time, but each time it happens it increases the error of the result.

We wanted a = 28

“Shared mutable state is the root of all evil.” -- several different people, all at the same time

Off To The Data Races!Techniques various and sundry for avoiding data races ...

● Locks! → a unit of execution acquires a lock, no other unit of execution can acquire the lock until it is released

○ C and C++

● Synchronized blocks/functions/methods! → somebody writes the locks for you○ Java

● Everything is read-only! → don’t need to worry about writes anymore○ Erlang

● There’s only one binding to an object at any time! → move, borrow, copy○ Rust

Leaving The Data Races

Leaving The Data RacesPony uses two rules to avoid data races:

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

Actors

ActorsActors store state and act on that state in response to messages

Actor● state● behaviors● functions

Actorsmessage3message4

message1message2 } Queue

Actorsmessage3message4

message1message2 } Queue

Actors

Get next message

message3message4

message1message2 } Queue

Actors

Get next message

Processmessage

message3message4

message1message2 } Queue

Actors

Get next message

Processmessage

Collect garbage

message3message4

message1message2 } Queue

Actors

Get next message

Processmessage

Collect garbage

message3message4

message1message2 } Queue

Actors

Get next message

Processmessage

Collect garbage

message3message4

message1message2 } Queue

In reality messages are processed in batches, GC is done between batches

Actors

a1.bar() a2.baz() a1.bar()

a3.dee() a4.doo() a3.doh()

a5.moo()

a8.fee() a7.foo()

a6.mee()

a7.fuz()

time

CPU1: thread1

CPU2: thread2

CPU3: thread3

CPU4: thread4

Actors run on threads (1 thread per CPU by default)

Actors

a1.bar() a2.baz() a1.bar()

a3.dee() a4.doo() a3.doh()

a5.moo()

a8.fee() a7.foo()

a6.mee()

a7.fuz()

time

CPU1: thread1

CPU2: thread2

CPU3: thread3

CPU4: thread4

Actors are assigned to a specific threada1, a2

a3, a4

a5, a6

a7, a8

Actors

a1.bar() a2.baz()1 a1.bar()

a3.dee() a4.doo() a3.doh()

a5.moo()

a8.fee() a7.foo()

a6.mee()

a7.fuz()

time

CPU1: thread1

CPU2: thread2

CPU3: thread3

CPU4: thread4

a2.baz()2

Behaviors cannot be preempted

Actors

a1.bar() a2.baz() a1.bar()

IDLE a1.baz() a3.doh()

a5.moo()

a8.fee() a7.foo()

a6.mee()

a7.fuz()

time

CPU1: thread1

CPU2: thread2

CPU3: thread3

CPU4: thread4

A idle thread “steal” work from another thread

Work for actor a1 “stolen” by thread2

Actors

a1.bar() a2.baz() a1.bar()

a1.buz() a4.doo() a3.doh()

a5.moo()

a8.fee() a7.foo()

a6.mee()

a7.fuz()

time

CPU1: thread1

CPU2: thread2

CPU3: thread3

CPU4: thread4

Actors process one message at a time (actors are effectively single-threaded)

Actors

a1 a3

a2

o1

Actors have references to objects and other actors

Actors

a1 a3

a2

o1

Actors have references to objects and other actors

References can be used to:* read from an object* write to an object* send messages to another actor

Actors

a1 a3

a2

o1

Actors have references to objects and other actors

References can be used to:* read from an object* write to an object* send messages to another actor

Reference Capabilities control whether reads and writes are allowed via a given reference. Any reference can be used to send a message.

Actors

a1 a3

a2

o1

Actors have references to objects and other actors

References can be used to:* read from an object* write to an object* send messages to another actor

Reference Capabilities control whether reads and writes are allowed via a given reference. Any reference can be used to send a message.

Note: send message ≠ read/write

Actors: An Example

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main

create(env)

run!

When the program starts, the Main actor is instantiated and a create message is sent to it.

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Maincreate(env)

The Main actor begins to process the create message.

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e

create(“howdy”)

create(env)

An instance of the Example actor is instantiated and a create message is sent to it with “howdy” as the argument.

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e

create(env)

o

create(“howdy)

create(env)

An instance of the the Other actor is instantiated and a create message is sent to it with env as the argument.

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Maincreate(env)create(“howdy)

foo(o)

e_text=”howdy”

o_env=envcreate(env)

The Main actor sends a foo message to the Example actor.

The Example actor sets the value of its _text field.

The Other actor sets the value of its _env field

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”howdy”

o_env=env

foo(o)1

foo(o)2

create(env)

The Main actor sends a foo message to the Example actor.

The Example actor sets the value of its _text field.

The Other actor sets the value of its _env field

foo(o)1

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”ydwoh”

o_env=env

foo(o)2

The Example actor processes the first foo message by first calling its rev method, which reverses the _text string.

foo(o)1

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”ydwoh”

o_env=env

foo(o)2 say(“ydwoh”)

The Example actor sends the string to the Other actor in a say message.

say(“ydwoh”)foo(o)2

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”howdy”

o_env=env

YDWOH

The Example actor processes the second foo message, which again reverses the _text string.

The Other actor processes the say message by printing the string that it received.

foo(o)2

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”howdy”

o_env=env

say(“howdy”)

YDWOH

The Example actor sends another say message to the Other actor.

say(“howdy”)

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”howdy”

o_env=env

YDWOHHOWDY

The Other actor processes the say message by printing the string that it received.

Actors: An Example

actor Example

var _text: String

new create(text: String) =>

_text = text

be foo(o: Other) =>

o.say(rev())

fun ref rev(): String val =>

_text = recover

_text.reverse()

end

_text

actor Other

let _env: Env

new create(env: Env) =>

_env = env

be say(s: String) =>

_env.out.print(s)

actor Main

new create(env: Env) =>

let e = Example("howdy")

let o = Other(env)

e.foo(o) // prints “ydwoh”

e.foo(o) // prints “howdy”

Main e_text=”howdy”

o_env=env

YDWOHHOWDY

All messages have been handled so the program can exit.

Reference Capabilities

Reference CapabilitiesRemember the Read Rule and the Write Rule:

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

Reference CapabilitiesReference capabilities control whether a given alias can be used to read or modify an object.

The collection of reference capabilities for aliases that refer to an object must be consistent with the Read Rule and the Write Rule.

Any alias to an actor, regardless of reference capability, can be used to send messages to that actor.

Reference CapabilitiesThere are six reference capabilities:

● iso - only one alias can be used to read or modify this object● trn - only one alias can modify this object, but more than one alias can be

used to read it● val - no alias can modify this object, but more than one alias can read from it● ref - more than one alias can read from this object, and more than alias can

modify this object● box - this alias can be used to read an object, there may more may not be

more than one other alias that can modify it● tag - this alias cannot be used to read or modify this object (but it can be

used to send a message or do an identity comparison)

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

● actor and class declarations○ class val Foo // a “Foo” type means “Foo val” unless otherwise specified

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

● actor and class declarations○ class val Foo // a “Foo” type means “Foo val” unless otherwise specified

● constructor declarations○ new val create() => // objects of this class will have a reference capability of val

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

● actor and class declarations○ class val Foo // a “Foo” type means “Foo val” unless otherwise specified

● constructor declarations○ new val create() => // objects of this class will have a reference capability of val

● function declarations○ fun ref bar() // bar()’s receiver must have a reference capability of ref

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

● actor and class declarations○ class val Foo // a “Foo” type means “Foo val” unless otherwise specified

● constructor declarations○ new val create() => // objects of this class will have a reference capability of val

● function declarations○ fun ref bar() // bar()’s receiver must have a reference capability of ref

● function return values○ fun f(): String ref // the String will have a reference capability of ref

Reference CapabilitiesReference capabilities can appear in

● variable, parameter, and field declarations○ let foo: Foo ref = Foo // foo’s reference capability is ref

● actor and class declarations○ class val Foo // a “Foo” type means “Foo val” unless otherwise specified

● constructor declarations○ new val create() => // objects of this class will have a reference capability of val

● function declarations○ fun ref bar() // bar()’s receiver must have a reference capability of ref

● function return values○ fun f(): String ref // the String will have a reference capability of ref

● recover blocks○ recover iso … end // the reference capability of the returned object will be iso

Reference CapabilitiesIf no reference capability is specified, the default reference capability for the given thing is used.

Reference Capabilitiesclass Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesSPOT THE REFERENCE CAPABILITIES!

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesSPOT THE EXPLICIT REFERENCE CAPABILITIES!

SPOT THE IMPLIED REFERENCE CAPABILITIES!

class ref Foo

class val Bar let v: U32 val new val create(vv: U32 val) => v = vv

actor tag Main new create(env: Env val) => let a: Foo iso = recover iso Foo end var b: Bar val = Bar(1) b = Bar(2) baz(b) fun box baz(c: Bar val): U32 val => c.v + 16

Reference CapabilitiesActors have a default reference capability of tag, objects created from classes have a default reference capability of ref

class ref Foo

class val Bar let v: U32 val new val create(vv: U32 val) => v = vv

actor tag Main new create(env: Env val) => let a: Foo iso = recover iso Foo end var b: Bar val = Bar(1) b = Bar(2) baz(b) fun box baz(c: Bar val): U32 val => c.v + 16

Reference CapabilitiesYou can change the implicit reference capability of a class (normally it is ref)

You can change the reference capability of the object generated by the constructor (normally it is ref)

class ref Foo

class val Bar let v: U32 val new val create(vv: U32 val) => v = vv

actor tag Main new create(env: Env val) => let a: Foo iso = recover iso Foo end var b: Bar val = Bar(1) b = Bar(2) baz(b) fun box baz(c: Bar val): U32 val => c.v + 16

Reference CapabilitiesYou can specify the type of reference capability that the receiver must have to call a function

class ref Foo

class val Bar let v: U32 val new val create(vv: U32 val) => v = vv

actor tag Main new create(env: Env val) => let a: Foo iso = recover iso Foo end var b: Bar val = Bar(1) b = Bar(2) baz(b) fun box baz(c: Bar val): U32 val => c.v + 16

Reference CapabilitiesYou can specify the type of reference capability that the receiver must have to call a function

This can get really tricky!

class ref Foo

class val Bar let v: U32 val new val create(vv: U32 val) => v = vv

actor tag Main new create(env: Env val) => let a: Foo iso = recover iso Foo end var b: Bar val = Bar(1) b = Bar(2) baz(b) fun box baz(c: Bar val): U32 val => c.v + 16

Reference CapabilitiesAn alias is a name given to a particular object in memory

Aliases are created when

● an object is assigned to a variable● an object is passed as an argument to a

method

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesAn alias is a name given to a particular object in memory

Aliases are created when

● an object is assigned to a variable● an object is passed as an argument to a

method

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesAn alias is a name given to a particular object in memory

Aliases are created when

● an object is assigned to a variable● an object is passed as an argument to a

method

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesAn alias is a name given to a particular object in memory

Aliases are created when

● an object is assigned to a variable● an object is passed as an argument to a

method

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesAn alias is a name given to a particular object in memory

Aliases are created when

● an object is assigned to a variable● an object is passed as an argument to a

method

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference CapabilitiesAn object may have more than one alias, possibly in more than one actor, but the combination of aliases must not violate the read rule and write rule.

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

class Foo

class val Bar let v: U32 new val create(vv: U32) => v = vv

actor Main new create(env: Env) => let a: Foo iso = recover Foo end var b = Bar(1) b = Bar(2) baz(b) fun baz(c: Bar): U32 => c.v + 16

Reference Capabilities: A Visual Guide

Reference Capabilities: iso (isolated)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

iso reference can read and modify an object. No other reference can read or modify the object.

object

alias1

alias2

alias3

Actor A Actor B

iso

Reference Capabilities: trn (transitional)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

trn reference can read and modify an object. No other reference can modify the object, but the actor may have other references that can read the object.

object

alias1

alias2

alias3

Actor A Actor B

trn

Reference Capabilities: ref (reference)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

ref reference can read and modify an object. Other references in the actor may be able to read or modify the object, but no other actor may have a reference that can read or modify it.

object

alias1

alias2

alias3

Actor A Actor B

ref

Reference Capabilities: val (value)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

val reference can read an object. The actor may have other references that can read the object, and other actors may have references that can read the object, but no actor may have a reference that can modify it.

object

alias1

alias2

alias3

Actor A Actor B

val

Reference Capabilities: box (box)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

object

alias1

alias2

alias3

Actor A Actor B

box

OR

object

alias1

alias2

alias3

Actor A Actor B

box

Reference Capabilities: box (box)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

object

alias1

alias2

alias3

Actor A Actor B

box

OR

object

alias1

alias2

alias3

Actor A Actor B

box

This looks like a val

This looks like a ref

A box capability is used when you want to create a new read-only reference to an object that is either val or ref.

Reference Capabilities: box (box)

Why do we have box?

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ???): I32 => x.v() + 1

What should the reference capability be?

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X val): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X val): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

val Doesn’t work because a val (x) can’t alias a ref (a)

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X val): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

val Doesn’t work because a val (x) can’t alias a ref (a)

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X val): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

val Doesn’t work because a val (x) can’t alias a ref (a)

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X box): I32 => x.v() + 1

Reference Capabilities: box (box)class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X ref): I32 => x.v() + 1

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X val): I32 => x.v() + 1

ref doesn’t work because a ref (x) can’t alias a val (b)

val Doesn’t work because a val (x) can’t alias a ref (a)

class X let v: I32 new create(v': I32) => v = v'

actor Main new create(env: Env) => let a: X ref = X(7) let b: X val = recover X(8) end bar(a) bar(b) fun bar(x: X box): I32 => x.v() + 1

box works because a box (x) can alias a ref (a) or a val (b)

Reference Capabilities: tag (tag)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

tag reference cannot read or modify an object, but it can be used to send the object messages if the object is an actor, or to compare identity. Other references may read or modify the object as long as they do not violate the Read Rule and the Write Rule.

object

alias1

alias2

alias3

Actor A Actor B

tag

Reference Capabilities: tag (tag)● The Read Rule: If an

actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

object

alias1

alias2

alias3

Actor A Actor B

tag

Example: alias2 can be a ref because this does not violate the Read Rule or Write Rule

tag reference cannot read or modify an object, but it can be used to send the object messages if the object is an actor, or to compare identity. Other references may read or modify the object as long as they do not violate the Read Rule and the Write Rule.

Reference CapabilitiesReadable → iso, trn, ref, val, box

Reference CapabilitiesReadable → iso, trn, ref, val, box

Writeable → iso, trn, ref

Reference CapabilitiesReadable → iso, trn, ref, val, box

Writeable → iso, trn, ref

Sendable → iso, val, tag

Objects with sendable reference capabilities can be sent to other actors in messages

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main Foo

foo

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main Foo

f

Bar

b

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main Foo

f

Bar

b

baz( )

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main Foo

f

Bar

b

baz( )

x

Reference Capabilities: Sending A valclass Bar

actor Foo be baz(x: Bar val) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover val Bar end f.baz(b)

Main Foo

f

Bar

b x

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

An actor’s default reference capability is tag

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main Foo

foo

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main Foo

f

Bar

b

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main Foo

f

Bar

b

baz( )

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main Foo

f

Bar

b

baz( )

x

Reference Capabilities: Sending A tagactor Bar

actor Foo be baz(x: Bar tag) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = Bar f.baz(b)

Main Foo

f

Bar

b x

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

foo

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b

consume causes b to give up it’s reference

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b

once we consume b, we can no longer use it

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b

baz( )

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b

baz( )

x

Reference Capabilities: Sending An isoclass Bar

actor Foo be baz(x: Bar iso) => // do something with x

actor Main new create(env: Env) => let f = Foo let b = recover iso Bar end f.baz(consume b)

Main Foo

f

Bar

b x

● The Read Rule: If an actor can read an object then no other actor can modify that object

● The Write Rule: If an actor can modify an object then no other actor can read or modify it

No More Data Races

No More Data RacesRemember this?

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

Expected:

2000000

Actual Run 1:

1987735

Actual Run 2:

1935010

Actual Run 3:

1941217

No More Data RacesRemember this?

global int a = 0

function inc() { for x in range(0, 1000001) { a = a + 1 }}

function main() { thread thread1 = Thread(inc) thread thread2 = Thread(inc) thread1.run() thread2.run() thread1.join() thread2.join() print(“a = “ + a)}

This program violates the Read Rule and Write Rule, because the variable a can be read and modified from multiple threads.

No More Data RacesA first pass at a Pony equivalent

use “collections”

class Counter var v: U64 = 0 fun ref inc() => v = v + 1

actor Inc be doit(c: Counter) => for x in range(0, 100001) do c.inc() end

actor Main new create(env: Env) => let c = Counter Inc.doit(c) Inc.doit(c) env.out.print(c.v.string())

No More Data RacesA first pass at a Pony equivalent

use “collections”

class Counter var v: U64 = 0 fun ref inc() => v = v + 1

actor Inc be doit(c: Counter) => for x in range(0, 100001) do c.inc() end

actor Main new create(env: Env) => let c = Counter Inc.doit(c) Inc.doit(c) env.out.print(c.v.string())

This doesn’t work because the two Inc actors try to read and write to the Counter

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

2000000

No More Data Racesuse “collections”

actor Counter var _count: U64 = 0 be increment() => _count = _count + 1 be print(env: Env) => env.out.print(_count.string())

actor Incrementer new create(counter: Counter, main: Main) => for x in Range(0, 1_000_001) do counter.increment() end main.finished(this)

actor Main let _finished_count = 0 let _counter: Counter = Counter let _env: Env new create(env: Env) => _env = env let inc1 = Incrementer(_counter, this) let inc2 = Incrementer(_counter, this) be finished() => _finished_count = _finished_count + 1 if _finished_count = 2 then _counter.print(env) end

The Counter actor “protects” the _count data structure

Sendence’s Experience With Pony

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Pony is a young language (not even 1.0.0 yet)

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Pony is a young language (not even 1.0.0 yet)

● limited documentation

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Pony is a young language (not even 1.0.0 yet)

● limited documentation● things change

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Pony is a young language (not even 1.0.0 yet)

● limited documentation● things change● there are some sharp edges (compiler bugs, runtime bugs)

Sendence’s Experience With PonyIt’s nice to catch errors a compile time rather than runtime

Pony is a young language (not even 1.0.0 yet)

● limited documentation● things change● there are some sharp edges (compiler bugs, runtime bugs)

“America is all about speed. Hot, nasty, badass speed.” -- Eleanor Roosevelt

PONY

Learn More(because I left a lot out)

Learn MoreUser Mailing List

● https://pony.groups.io/g/user

Website

● https://www.ponylang.org

IRC

● freenode #ponylang

Contribute

ContributeDeveloper Mailing List

● https://pony.groups.io/g/dev

Github

● Pony compiler → https://github.com/ponylang/ponyc● RFCs → https://github.com/ponylang/rfcs

Thank You

Questions