SlideShare a Scribd company logo
1 of 49
Download to read offline
Project Gålbma:
Actors vs Types
Dr. Roland Kuhn
@rolandkuhn — Akka Tech Lead
Motivation
Motivation
3
case class Get
case class Got(contents: Map[String, ActorRef])
class Server extends Actor {
var map = Map.empty[String, ActorRef]
def receive = {
case Get =>
sender ! Got(map)
}
}
4
case class GetRef(name: String)
case class GetRefReply(ref: Option[ActorRef])
class Client(server: ActorRef) extends Actor {
def receive = {
case GetRef(name) =>
val worker = context.actorOf(Worker.props(name, sender()))
server.tell(Get, worker)
}
}
object Worker {
def props(name: String, replyTo: ActorRef) =
Props(new Worker(name, replyTo))
}
class Worker(name: String, replyTo: ActorRef) extends Actor {
def receive = {
case Got(map) =>
replyTo ! GetRefReply(map.get(name))
context.stop(self)
}
}
5
case class Get(id: Int)
case class Got(id: Int, contents: Map[String, ActorRef])
class Server extends Actor {
var map = Map.empty[String, ActorRef]
def receive = {
case Get(id) =>
sender ! Got(id, map)
}
}
6
case class GetRef(name: String)
case class GetRefReply(ref: Option[ActorRef])
class Client(server: ActorRef) extends Actor {
def receive = {
case GetRef(name) =>
val worker = context.actorOf(Worker.props(name, sender()))
server.tell(Get, worker)
}
}
object Worker {
def props(name: String, replyTo: ActorRef) =
Props(new Worker(name, replyTo))
}
class Worker(name: String, replyTo: ActorRef) extends Actor {
def receive = {
case Got(id, map) =>
replyTo ! GetRefReply(map.get(name))
context.stop(self)
}
}
7
class Asker(server: ActorRef) extends Actor {
implicit val timeout = Timeout(1.second)
import context.dispatcher
def receive = {
case GetRef(name) =>
(server ? Get(42))
.mapTo[Got]
.map(got => GetRefReply(got.contents get name))
.pipeTo(sender())
}
}
Failed Attempts
Akka 1.2: Channel[-T]
9
/**
* Abstraction for unification of sender and senderFuture for later reply.
* Can be stored away and used at a later point in time.
*
* The possible reply channel which can be passed into ! and tryTell is always
* untyped, as there is no way to utilize its real static type without
* requiring runtime-costly manifests.
*/
trait Channel[-T] extends japi.Channel[T] {
/**
* Scala API. <p/>
* Sends the specified message to the channel.
*/
def !(msg: T)(implicit sender: UntypedChannel): Unit
...
}
Akka 2.1: Typed Channels
10
Akka 2.1: Typed Channels
11
Akka 2.1: Typed Channels
12
The Failures Summarized
• first no clear vision of the goal
• then trying to go too far
• too complicated to declare
• white-box macros required
• not bold enough
• untyped Actors have features that are incompatible with
static typing
13
The Solution
What we want: Parameterized ActorRef
15
object Server {
case class Get(id: Int)(val replyTo: ActorRef[Got])
case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]])
}
object Client {
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply])
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
}
val server: ActorRef[Server.Get] = ???
val behavior: PartialFunction[Any, Unit] = {
case g @ GetRef(name) =>
(server ? Server.Get(42))
.map(got => g.replyTo ! GetRefReply(got.contents get name))
}
What we want: Parameterized ActorRef
16
object Server {
case class Get(id: Int)(val replyTo: ActorRef[Got])
case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]])
}
object Client {
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply])
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
}
val server: ActorRef[Server.Get] = ???
val behavior: PartialFunction[Any, Unit] = {
case g @ GetRef(name) =>
(server ? Server.Get(42))
.map(got => g.replyTo ! GetRefReply(got.contents get name))
}
What we want: Parameterized ActorRef
17
object Server {
case class Get(id: Int)(val replyTo: ActorRef[Got])
case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]])
}
object Client {
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply])
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
}
val server: ActorRef[Server.Get] = ???
val behavior: PartialFunction[Any, Unit] = {
case g @ GetRef(name) =>
(server ? Server.Get(42))
.map(got => g.replyTo ! GetRefReply(got.contents get name))
}
The Guiding Principle
• build everything around ActorRef[-T]
• do not use macros or type calculations that Java
cannot do (i.e. “keep it simple”)
• remove all features that are incompatible with this
• in particular the automatic “sender” capture must go
18
Possible Plan
• add type parameter to ActorRef, Actor, …
• remove sender()
• type Receive = PartialFunction[T, Unit]
• restrict context.become to this type
• type-safety achieved—everyone happy!
19
But why stop here?
« … and determine the behavior to be
applied to the next message.»
— Carl Hewitt, 1973
gålbma (sami) — kolme (finnish): THREE
We have one chance to rectify some things
Project Gålbma
• distill an Actor to its essence: the Behavior
• everything is a message—for real this time
• remove the danger to close over Actor environment
• behavior composition
• allow completely pure formulation of Actors
23
Behavior is King, no more Actor trait
24
object Server {
sealed trait Command
case class Get(id: Int)(val replyTo: ActorRef[Got]) extends Command
case class Put(name: String, ref: ActorRef[OtherCommand]) extends Command
case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]])
val initial: Behavior[Command] = withMap(Map.empty)
private def withMap(map: Map[String, ActorRef[OtherCommand]]) =
Total[Command] {
case g @ Get(id) =>
g.replyTo ! Got(id, Map.empty)
Same
case Put(name, ref) =>
withMap(map.updated(name, ref))
}
}
No More Closing over ActorContext
• ActorContext is passed in for every message
• processing a message returns the next behavior
• lifecycle hooks, Terminated and ReceiveTimeout
are management “signals”
25
final case class Total[T](behavior: T => Behavior[T]) extends Behavior[T] {
override def management(ctx: ActorContext[T], msg: Signal): Behavior[T] = Unhandled
override def message(ctx: ActorContext[T], msg: T): Behavior[T] = behavior(msg)
override def toString = s"Total(${LineNumbers(behavior)})"
}
Everything behaves like a Message
• ActorContext remains the system interface:
• spawn, stop, watch, unwatch, setReceiveTimeout, schedule,
executionContext, spawnAdapter, props, system, self
• actorOf — for interoperability with untyped Actors
26
Full[Command] {
case Msg(ctx, cmd) => // def receive
case Sig(ctx, PreStart) => // def preStart()
case Sig(ctx, PreRestart(ex)) => // def preRestart(...)
case Sig(ctx, PostRestart(ex)) => // def postRestart(...)
case Sig(ctx, PostStop) => // def postStop()
case Sig(ctx, Failed(ex, child)) => // val supervisorStrategy
case Sig(ctx, ReceiveTimeout) => // case ReceiveTimeout
case Sig(ctx, Terminated(ref)) => // case Terminated(...)
}
27
object Client {
sealed trait Command
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command
case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]])
extends Command
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
def initial(server: ActorRef[Server.Command]) =
ContextAware[Command] { ctx =>
val adapter =
ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents))
behv(0, Map.empty)(adapter, server)
}
def behv(nextId: Int,
replies: Map[Int, (String, ActorRef[GetRefReply])])(
implicit adapter: ActorRef[Server.Got],
server: ActorRef[Server.Command]): Behavior[Command] =
Total {
case g @ GetRef(name) =>
server ! Server.Get(nextId)(adapter)
behv(nextId + 1, replies.updated(nextId, name -> g.replyTo))
case GotWrapper(id, contents) =>
replies get id map (p => p._2 ! GetRefReply(contents get p._1))
behv(nextId, replies - id)
}
}
28
object Client {
sealed trait Command
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command
case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]])
extends Command
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
def initial(server: ActorRef[Server.Command]) =
ContextAware[Command] { ctx =>
val adapter: ActorRef[Server.Got] =
ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents))
behv(0, Map.empty)(adapter, server)
}
def behv(nextId: Int,
replies: Map[Int, (String, ActorRef[GetRefReply])])(
implicit adapter: ActorRef[Server.Got],
server: ActorRef[Server.Command]): Behavior[Command] =
Total {
case g @ GetRef(name) =>
server ! Server.Get(nextId)(adapter)
behv(nextId + 1, replies.updated(nextId, name -> g.replyTo))
case GotWrapper(id, contents) =>
replies get id map (p => p._2 ! GetRefReply(contents get p._1))
behv(nextId, replies - id)
}
}
29
object Client {
sealed trait Command
case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command
case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]])
extends Command
case class GetRefReply(ref: Option[ActorRef[OtherCommand]])
def initial(server: ActorRef[Server.Command]) =
ContextAware[Command] { ctx =>
val adapter =
ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents))
behv(0, Map.empty)(adapter, server)
}
def behv(nextId: Int,
replies: Map[Int, (String, ActorRef[GetRefReply])]
)(implicit adapter: ActorRef[Server.Got],
server: ActorRef[Server.Command]): Behavior[Command] =
Total {
case g @ GetRef(name) =>
server ! Server.Get(nextId)(adapter)
behv(nextId + 1, replies.updated(nextId, name -> g.replyTo))
case GotWrapper(id, contents) =>
replies get id map (p => p._2 ! GetRefReply(contents get p._1))
behv(nextId, replies - id)
}
}
Under the Hood
The Implementation
• independent add-on library
• layered completely on top of untyped Actors
• currently 2kLOC main + 1.7kLOC tests
• fully interoperable
31
The most important interface: Behavior[T]
• Behaviors:
• Full, FullTotal, Total, Partial, Static
• Decorators:
• ContextAware, SelfAware, SynchronousSelf, Tap
• Combinators:
• And, Or, Widened
32
abstract class Behavior[T] {
def management(ctx: ActorContext[T], msg: Signal): Behavior[T]
def message(ctx: ActorContext[T], msg: T): Behavior[T]
def narrow[U <: T]: Behavior[U] = this.asInstanceOf[Behavior[U]]
}
ActorSystem ≈ ActorRef
33
object Demo extends App {
implicit val t = Timeout(1.second)
val guardian = ContextAware[Client.Command] { ctx =>
val server = ctx.spawn(Props(Server.initial), "server")
val client = ctx.spawn(Props(Client.initial(server)), "client")
Static {
case msg => client ! msg
}
}
val system = ActorSystem("Demo", Props(guardian))
import system.executionContext
system ? Client.GetRef("X") map println foreach (_ => system.terminate())
}
Testing
Behavior Rulez!
• decoupling of logic from execution mechanism
• synchronous behavioral tests of individual Actors
• mock ActorContext allows inspection of effects
35
36
object `A Receptionist` {
def `must register a service`(): Unit = {
val ctx = new EffectfulActorContext("register", Props(behavior), system)
val a = Inbox.sync[ServiceA]("a")
val r = Inbox.sync[Registered[_]]("r")
ctx.run(Register(ServiceKeyA, a.ref)(r.ref))
ctx.getAllEffects() should be(Effect.Watched(a.ref) :: Nil)
r.receiveMsg() should be(Registered(ServiceKeyA, a.ref))
val q = Inbox.sync[Listing[ServiceA]]("q")
ctx.run(Find(ServiceKeyA)(q.ref))
ctx.getAllEffects() should be(Nil)
q.receiveMsg() should be(Listing(ServiceKeyA, Set(a.ref)))
assertEmpty(a, r, q)
}
...
}
What can we do with it?
Encoding Types with Members
38
class MyClass {
def myMethod(id: Int): String
def otherMethod(name: String): Unit
protected def helper(arg: Double): Unit
}
Encoding Types with Members
• Typed Actors provide complete modules with members
• Typed Actors can encode more flexible access privileges
• more verbose due to syntax being optimized for classes
39
object MyClass {
sealed trait AllCommand
sealed trait Command extends AllCommand
case class MyMethod(id: Int)(replyTo: ActorRef[String]) extends Command
case class OtherMethod(name: String) extends Command
case class Helper(arg: Double) extends AllCommand
val behavior: Behavior[Command] = behavior(42).narrow
private def behavior(x: Int): Behavior[AllCommand] = ???
}
Calling Methods
40
object MyClassDemo {
import MyClass._
val myClass: MyClass = ???
val myActor: ActorRef[Command] = ???
implicit val t: Timeout = ???
myClass.otherMethod("John")
myActor!OtherMethod("John")
val result = myClass.myMethod(42)
val future = myActor?MyMethod(42)
}
But Actors can do more: Protocols
41
object Protocol {
case class GetSession(replyTo: ActorRef[GetSessionResult])
sealed trait GetSessionResult
case class ActiveSession(service: ActorRef[SessionCommand])
extends GetSessionResult with AuthenticateResult
case class NewSession(auth: ActorRef[Authenticate])
extends GetSessionResult
case class Authenticate(username: String,
password: String,
replyTo: ActorRef[AuthenticateResult])
sealed trait AuthenticateResult
case object FailedSession extends AuthenticateResult
trait SessionCommand
}
But Actors can do more: Protocols
42
What can we express?
• everything a classical module with methods can
• pass object references as inputs and outputs
• patterns beyond request–response
• dynamic proxying / delegation
43
What can we NOT express?
• any dynamic behavior (e.g. internal state changes)
• session invalidation
44
Summary and Outlook
Current Status
• part of Akka 2.4-M1
• http://doc.akka.io/docs/akka/2.4-M1/scala/typed.html
• only bare Actors
• no persistence
• no stash
• no at-least-once delivery
• no Java API yet (but taken into account already)
46
Next Steps
• proper Java API (probably in 2.4-M2)
• Receptionist plus akka-distributed-data for Cluster
• port Actor-based APIs to typed ones (e.g. Akka IO)
• add FSM support with transition triggers
• completely pure Actor implementation,

«Actor Action Monad» (inspired by JoinCalculus)
• listen to community feedback
47
… and in the far future:
• reap internal benefits by inverting implementation:
• remove sender field (and thus Envelope)
• make untyped Actor a DSL layer on top of Akka Typed
• declare it non-experimental
48
©Typesafe 2015 – All Rights Reserved

More Related Content

What's hot

Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyIván López Martín
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meetMario Fusco
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsIván López Martín
 
Python programming: Anonymous functions, String operations
Python programming: Anonymous functions, String operationsPython programming: Anonymous functions, String operations
Python programming: Anonymous functions, String operationsMegha V
 
Introduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demoIntroduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demoMuhammad Abdullah
 
CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29Bilal Ahmed
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsMiguel Angel Horna
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scalaXing
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Waytdc-globalcode
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsJohn De Goes
 
The Logical Burrito - pattern matching, term rewriting and unification
The Logical Burrito - pattern matching, term rewriting and unificationThe Logical Burrito - pattern matching, term rewriting and unification
The Logical Burrito - pattern matching, term rewriting and unificationNorman Richards
 
The Ring programming language version 1.6 book - Part 40 of 189
The Ring programming language version 1.6 book - Part 40 of 189The Ring programming language version 1.6 book - Part 40 of 189
The Ring programming language version 1.6 book - Part 40 of 189Mahmoud Samir Fayed
 
awesome groovy
awesome groovyawesome groovy
awesome groovyPaul King
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objectsHusain Dalal
 

What's hot (20)

Madrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovyMadrid gug - sacando partido a las transformaciones ast de groovy
Madrid gug - sacando partido a las transformaciones ast de groovy
 
Scala - where objects and functions meet
Scala - where objects and functions meetScala - where objects and functions meet
Scala - where objects and functions meet
 
G3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy AnnotationsG3 Summit 2016 - Taking Advantage of Groovy Annotations
G3 Summit 2016 - Taking Advantage of Groovy Annotations
 
Python programming: Anonymous functions, String operations
Python programming: Anonymous functions, String operationsPython programming: Anonymous functions, String operations
Python programming: Anonymous functions, String operations
 
Knolx session
Knolx sessionKnolx session
Knolx session
 
Scala
ScalaScala
Scala
 
Introduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demoIntroduction to kotlin + spring boot demo
Introduction to kotlin + spring boot demo
 
core.logic introduction
core.logic introductioncore.logic introduction
core.logic introduction
 
CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29CS101- Introduction to Computing- Lecture 29
CS101- Introduction to Computing- Lecture 29
 
Meetup slides
Meetup slidesMeetup slides
Meetup slides
 
Algorithm and Programming (Record)
Algorithm and Programming (Record)Algorithm and Programming (Record)
Algorithm and Programming (Record)
 
The Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation PlatformsThe Challenge of Bringing FEZ to PlayStation Platforms
The Challenge of Bringing FEZ to PlayStation Platforms
 
An introduction to scala
An introduction to scalaAn introduction to scala
An introduction to scala
 
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin WayTDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
TDC218SP | Trilha Kotlin - DSLs in a Kotlin Way
 
Scalaz 8 vs Akka Actors
Scalaz 8 vs Akka ActorsScalaz 8 vs Akka Actors
Scalaz 8 vs Akka Actors
 
The Logical Burrito - pattern matching, term rewriting and unification
The Logical Burrito - pattern matching, term rewriting and unificationThe Logical Burrito - pattern matching, term rewriting and unification
The Logical Burrito - pattern matching, term rewriting and unification
 
The Ring programming language version 1.6 book - Part 40 of 189
The Ring programming language version 1.6 book - Part 40 of 189The Ring programming language version 1.6 book - Part 40 of 189
The Ring programming language version 1.6 book - Part 40 of 189
 
Scala 2013 review
Scala 2013 reviewScala 2013 review
Scala 2013 review
 
awesome groovy
awesome groovyawesome groovy
awesome groovy
 
Groovy grails types, operators, objects
Groovy grails types, operators, objectsGroovy grails types, operators, objects
Groovy grails types, operators, objects
 

Viewers also liked

Distributed systems vs compositionality
Distributed systems vs compositionalityDistributed systems vs compositionality
Distributed systems vs compositionalityRoland Kuhn
 
The Newest in Session Types
The Newest in Session TypesThe Newest in Session Types
The Newest in Session TypesRoland Kuhn
 
Akka Streams and HTTP
Akka Streams and HTTPAkka Streams and HTTP
Akka Streams and HTTPRoland Kuhn
 
Go Reactive: Blueprint for Future Applications
Go Reactive: Blueprint for Future ApplicationsGo Reactive: Blueprint for Future Applications
Go Reactive: Blueprint for Future ApplicationsRoland Kuhn
 
Reactive Design Patterns — J on the Beach
Reactive Design Patterns — J on the BeachReactive Design Patterns — J on the Beach
Reactive Design Patterns — J on the BeachRoland Kuhn
 
Akka and AngularJS – Reactive Applications in Practice
Akka and AngularJS – Reactive Applications in PracticeAkka and AngularJS – Reactive Applications in Practice
Akka and AngularJS – Reactive Applications in PracticeRoland Kuhn
 
Go Reactive: Event-Driven, Scalable, Resilient & Responsive Systems
Go Reactive: Event-Driven, Scalable, Resilient & Responsive SystemsGo Reactive: Event-Driven, Scalable, Resilient & Responsive Systems
Go Reactive: Event-Driven, Scalable, Resilient & Responsive SystemsJonas Bonér
 
Reactive Streams: Handling Data-Flow the Reactive Way
Reactive Streams: Handling Data-Flow the Reactive WayReactive Streams: Handling Data-Flow the Reactive Way
Reactive Streams: Handling Data-Flow the Reactive WayRoland Kuhn
 

Viewers also liked (8)

Distributed systems vs compositionality
Distributed systems vs compositionalityDistributed systems vs compositionality
Distributed systems vs compositionality
 
The Newest in Session Types
The Newest in Session TypesThe Newest in Session Types
The Newest in Session Types
 
Akka Streams and HTTP
Akka Streams and HTTPAkka Streams and HTTP
Akka Streams and HTTP
 
Go Reactive: Blueprint for Future Applications
Go Reactive: Blueprint for Future ApplicationsGo Reactive: Blueprint for Future Applications
Go Reactive: Blueprint for Future Applications
 
Reactive Design Patterns — J on the Beach
Reactive Design Patterns — J on the BeachReactive Design Patterns — J on the Beach
Reactive Design Patterns — J on the Beach
 
Akka and AngularJS – Reactive Applications in Practice
Akka and AngularJS – Reactive Applications in PracticeAkka and AngularJS – Reactive Applications in Practice
Akka and AngularJS – Reactive Applications in Practice
 
Go Reactive: Event-Driven, Scalable, Resilient & Responsive Systems
Go Reactive: Event-Driven, Scalable, Resilient & Responsive SystemsGo Reactive: Event-Driven, Scalable, Resilient & Responsive Systems
Go Reactive: Event-Driven, Scalable, Resilient & Responsive Systems
 
Reactive Streams: Handling Data-Flow the Reactive Way
Reactive Streams: Handling Data-Flow the Reactive WayReactive Streams: Handling Data-Flow the Reactive Way
Reactive Streams: Handling Data-Flow the Reactive Way
 

Similar to Project Gålbma – Actors vs Types

Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesTomer Gabel
 
Scaling modern JVM applications with Akka toolkit
Scaling modern JVM applications with Akka toolkitScaling modern JVM applications with Akka toolkit
Scaling modern JVM applications with Akka toolkitBojan Babic
 
Message-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applicationsMessage-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applicationsAndrii Lashchenko
 
Improving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinImproving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinIain Hull
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In JavaAndrei Solntsev
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfHiroshi Ono
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Codestasimus
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfIain Hull
 
Julio Capote, Twitter
Julio Capote, TwitterJulio Capote, Twitter
Julio Capote, TwitterOntico
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kirill Rozov
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009David Pollak
 
Improving Correctness with Types
Improving Correctness with TypesImproving Correctness with Types
Improving Correctness with TypesIain Hull
 

Similar to Project Gålbma – Actors vs Types (20)

Akka patterns
Akka patternsAkka patterns
Akka patterns
 
Scala Back to Basics: Type Classes
Scala Back to Basics: Type ClassesScala Back to Basics: Type Classes
Scala Back to Basics: Type Classes
 
Scaling modern JVM applications with Akka toolkit
Scaling modern JVM applications with Akka toolkitScaling modern JVM applications with Akka toolkit
Scaling modern JVM applications with Akka toolkit
 
Akka tips
Akka tipsAkka tips
Akka tips
 
Message-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applicationsMessage-based communication patterns in distributed Akka applications
Message-based communication patterns in distributed Akka applications
 
Improving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con BerlinImproving Correctness With Type - Goto Con Berlin
Improving Correctness With Type - Goto Con Berlin
 
Functional Programming In Java
Functional Programming In JavaFunctional Programming In Java
Functional Programming In Java
 
25-functions.ppt
25-functions.ppt25-functions.ppt
25-functions.ppt
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdfpragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
pragmaticrealworldscalajfokus2009-1233251076441384-2.pdf
 
Groovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony CodeGroovy vs Boilerplate and Ceremony Code
Groovy vs Boilerplate and Ceremony Code
 
Improving Correctness with Types Kats Conf
Improving Correctness with Types Kats ConfImproving Correctness with Types Kats Conf
Improving Correctness with Types Kats Conf
 
Julio Capote, Twitter
Julio Capote, TwitterJulio Capote, Twitter
Julio Capote, Twitter
 
Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3Kotlin Advanced - Apalon Kotlin Sprint Part 3
Kotlin Advanced - Apalon Kotlin Sprint Part 3
 
Beginning Scala Svcc 2009
Beginning Scala Svcc 2009Beginning Scala Svcc 2009
Beginning Scala Svcc 2009
 
Improving Correctness with Types
Improving Correctness with TypesImproving Correctness with Types
Improving Correctness with Types
 
ScalaBlitz
ScalaBlitzScalaBlitz
ScalaBlitz
 
Scala best practices
Scala best practicesScala best practices
Scala best practices
 

Recently uploaded

Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxRTS corp
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfYashikaSharma391629
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEEVICTOR MAESTRE RAMIREZ
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecturerahul_net
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationBradBedford3
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Matt Ray
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesŁukasz Chruściel
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Rob Geurden
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)jennyeacort
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...Technogeeks
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesPhilip Schwarz
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfMarharyta Nedzelska
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalLionel Briand
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfFerryKemperman
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaHanief Utama
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Velvetech LLC
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024StefanoLambiase
 

Recently uploaded (20)

Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptxReal-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
Real-time Tracking and Monitoring with Cargo Cloud Solutions.pptx
 
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdfInnovate and Collaborate- Harnessing the Power of Open Source Software.pdf
Innovate and Collaborate- Harnessing the Power of Open Source Software.pdf
 
Cloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEECloud Data Center Network Construction - IEEE
Cloud Data Center Network Construction - IEEE
 
2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva2.pdf Ejercicios de programación competitiva
2.pdf Ejercicios de programación competitiva
 
Understanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM ArchitectureUnderstanding Flamingo - DeepMind's VLM Architecture
Understanding Flamingo - DeepMind's VLM Architecture
 
How to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion ApplicationHow to submit a standout Adobe Champion Application
How to submit a standout Adobe Champion Application
 
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
Open Source Summit NA 2024: Open Source Cloud Costs - OpenCost's Impact on En...
 
Unveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New FeaturesUnveiling the Future: Sylius 2.0 New Features
Unveiling the Future: Sylius 2.0 New Features
 
Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...Simplifying Microservices & Apps - The art of effortless development - Meetup...
Simplifying Microservices & Apps - The art of effortless development - Meetup...
 
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
Call Us🔝>༒+91-9711147426⇛Call In girls karol bagh (Delhi)
 
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort ServiceHot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
Hot Sexy call girls in Patel Nagar🔝 9953056974 🔝 escort Service
 
Advantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your BusinessAdvantages of Odoo ERP 17 for Your Business
Advantages of Odoo ERP 17 for Your Business
 
What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...What is Advanced Excel and what are some best practices for designing and cre...
What is Advanced Excel and what are some best practices for designing and cre...
 
Folding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a seriesFolding Cheat Sheet #4 - fourth in a series
Folding Cheat Sheet #4 - fourth in a series
 
A healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdfA healthy diet for your Java application Devoxx France.pdf
A healthy diet for your Java application Devoxx France.pdf
 
Precise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive GoalPrecise and Complete Requirements? An Elusive Goal
Precise and Complete Requirements? An Elusive Goal
 
Introduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdfIntroduction Computer Science - Software Design.pdf
Introduction Computer Science - Software Design.pdf
 
React Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief UtamaReact Server Component in Next.js by Hanief Utama
React Server Component in Next.js by Hanief Utama
 
Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...Software Project Health Check: Best Practices and Techniques for Your Product...
Software Project Health Check: Best Practices and Techniques for Your Product...
 
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
Dealing with Cultural Dispersion — Stefano Lambiase — ICSE-SEIS 2024
 

Project Gålbma – Actors vs Types

  • 1. Project Gålbma: Actors vs Types Dr. Roland Kuhn @rolandkuhn — Akka Tech Lead
  • 3. Motivation 3 case class Get case class Got(contents: Map[String, ActorRef]) class Server extends Actor { var map = Map.empty[String, ActorRef] def receive = { case Get => sender ! Got(map) } }
  • 4. 4 case class GetRef(name: String) case class GetRefReply(ref: Option[ActorRef]) class Client(server: ActorRef) extends Actor { def receive = { case GetRef(name) => val worker = context.actorOf(Worker.props(name, sender())) server.tell(Get, worker) } } object Worker { def props(name: String, replyTo: ActorRef) = Props(new Worker(name, replyTo)) } class Worker(name: String, replyTo: ActorRef) extends Actor { def receive = { case Got(map) => replyTo ! GetRefReply(map.get(name)) context.stop(self) } }
  • 5. 5 case class Get(id: Int) case class Got(id: Int, contents: Map[String, ActorRef]) class Server extends Actor { var map = Map.empty[String, ActorRef] def receive = { case Get(id) => sender ! Got(id, map) } }
  • 6. 6 case class GetRef(name: String) case class GetRefReply(ref: Option[ActorRef]) class Client(server: ActorRef) extends Actor { def receive = { case GetRef(name) => val worker = context.actorOf(Worker.props(name, sender())) server.tell(Get, worker) } } object Worker { def props(name: String, replyTo: ActorRef) = Props(new Worker(name, replyTo)) } class Worker(name: String, replyTo: ActorRef) extends Actor { def receive = { case Got(id, map) => replyTo ! GetRefReply(map.get(name)) context.stop(self) } }
  • 7. 7 class Asker(server: ActorRef) extends Actor { implicit val timeout = Timeout(1.second) import context.dispatcher def receive = { case GetRef(name) => (server ? Get(42)) .mapTo[Got] .map(got => GetRefReply(got.contents get name)) .pipeTo(sender()) } }
  • 9. Akka 1.2: Channel[-T] 9 /** * Abstraction for unification of sender and senderFuture for later reply. * Can be stored away and used at a later point in time. * * The possible reply channel which can be passed into ! and tryTell is always * untyped, as there is no way to utilize its real static type without * requiring runtime-costly manifests. */ trait Channel[-T] extends japi.Channel[T] { /** * Scala API. <p/> * Sends the specified message to the channel. */ def !(msg: T)(implicit sender: UntypedChannel): Unit ... }
  • 10. Akka 2.1: Typed Channels 10
  • 11. Akka 2.1: Typed Channels 11
  • 12. Akka 2.1: Typed Channels 12
  • 13. The Failures Summarized • first no clear vision of the goal • then trying to go too far • too complicated to declare • white-box macros required • not bold enough • untyped Actors have features that are incompatible with static typing 13
  • 15. What we want: Parameterized ActorRef 15 object Server { case class Get(id: Int)(val replyTo: ActorRef[Got]) case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) } object Client { case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) } val server: ActorRef[Server.Get] = ??? val behavior: PartialFunction[Any, Unit] = { case g @ GetRef(name) => (server ? Server.Get(42)) .map(got => g.replyTo ! GetRefReply(got.contents get name)) }
  • 16. What we want: Parameterized ActorRef 16 object Server { case class Get(id: Int)(val replyTo: ActorRef[Got]) case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) } object Client { case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) } val server: ActorRef[Server.Get] = ??? val behavior: PartialFunction[Any, Unit] = { case g @ GetRef(name) => (server ? Server.Get(42)) .map(got => g.replyTo ! GetRefReply(got.contents get name)) }
  • 17. What we want: Parameterized ActorRef 17 object Server { case class Get(id: Int)(val replyTo: ActorRef[Got]) case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) } object Client { case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) } val server: ActorRef[Server.Get] = ??? val behavior: PartialFunction[Any, Unit] = { case g @ GetRef(name) => (server ? Server.Get(42)) .map(got => g.replyTo ! GetRefReply(got.contents get name)) }
  • 18. The Guiding Principle • build everything around ActorRef[-T] • do not use macros or type calculations that Java cannot do (i.e. “keep it simple”) • remove all features that are incompatible with this • in particular the automatic “sender” capture must go 18
  • 19. Possible Plan • add type parameter to ActorRef, Actor, … • remove sender() • type Receive = PartialFunction[T, Unit] • restrict context.become to this type • type-safety achieved—everyone happy! 19
  • 20. But why stop here?
  • 21. « … and determine the behavior to be applied to the next message.» — Carl Hewitt, 1973
  • 22. gålbma (sami) — kolme (finnish): THREE We have one chance to rectify some things
  • 23. Project Gålbma • distill an Actor to its essence: the Behavior • everything is a message—for real this time • remove the danger to close over Actor environment • behavior composition • allow completely pure formulation of Actors 23
  • 24. Behavior is King, no more Actor trait 24 object Server { sealed trait Command case class Get(id: Int)(val replyTo: ActorRef[Got]) extends Command case class Put(name: String, ref: ActorRef[OtherCommand]) extends Command case class Got(id: Int, contents: Map[String, ActorRef[OtherCommand]]) val initial: Behavior[Command] = withMap(Map.empty) private def withMap(map: Map[String, ActorRef[OtherCommand]]) = Total[Command] { case g @ Get(id) => g.replyTo ! Got(id, Map.empty) Same case Put(name, ref) => withMap(map.updated(name, ref)) } }
  • 25. No More Closing over ActorContext • ActorContext is passed in for every message • processing a message returns the next behavior • lifecycle hooks, Terminated and ReceiveTimeout are management “signals” 25 final case class Total[T](behavior: T => Behavior[T]) extends Behavior[T] { override def management(ctx: ActorContext[T], msg: Signal): Behavior[T] = Unhandled override def message(ctx: ActorContext[T], msg: T): Behavior[T] = behavior(msg) override def toString = s"Total(${LineNumbers(behavior)})" }
  • 26. Everything behaves like a Message • ActorContext remains the system interface: • spawn, stop, watch, unwatch, setReceiveTimeout, schedule, executionContext, spawnAdapter, props, system, self • actorOf — for interoperability with untyped Actors 26 Full[Command] { case Msg(ctx, cmd) => // def receive case Sig(ctx, PreStart) => // def preStart() case Sig(ctx, PreRestart(ex)) => // def preRestart(...) case Sig(ctx, PostRestart(ex)) => // def postRestart(...) case Sig(ctx, PostStop) => // def postStop() case Sig(ctx, Failed(ex, child)) => // val supervisorStrategy case Sig(ctx, ReceiveTimeout) => // case ReceiveTimeout case Sig(ctx, Terminated(ref)) => // case Terminated(...) }
  • 27. 27 object Client { sealed trait Command case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]]) extends Command case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) def initial(server: ActorRef[Server.Command]) = ContextAware[Command] { ctx => val adapter = ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents)) behv(0, Map.empty)(adapter, server) } def behv(nextId: Int, replies: Map[Int, (String, ActorRef[GetRefReply])])( implicit adapter: ActorRef[Server.Got], server: ActorRef[Server.Command]): Behavior[Command] = Total { case g @ GetRef(name) => server ! Server.Get(nextId)(adapter) behv(nextId + 1, replies.updated(nextId, name -> g.replyTo)) case GotWrapper(id, contents) => replies get id map (p => p._2 ! GetRefReply(contents get p._1)) behv(nextId, replies - id) } }
  • 28. 28 object Client { sealed trait Command case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]]) extends Command case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) def initial(server: ActorRef[Server.Command]) = ContextAware[Command] { ctx => val adapter: ActorRef[Server.Got] = ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents)) behv(0, Map.empty)(adapter, server) } def behv(nextId: Int, replies: Map[Int, (String, ActorRef[GetRefReply])])( implicit adapter: ActorRef[Server.Got], server: ActorRef[Server.Command]): Behavior[Command] = Total { case g @ GetRef(name) => server ! Server.Get(nextId)(adapter) behv(nextId + 1, replies.updated(nextId, name -> g.replyTo)) case GotWrapper(id, contents) => replies get id map (p => p._2 ! GetRefReply(contents get p._1)) behv(nextId, replies - id) } }
  • 29. 29 object Client { sealed trait Command case class GetRef(name: String)(val replyTo: ActorRef[GetRefReply]) extends Command case class GotWrapper(id: Int, contents: Map[String, ActorRef[OtherCommand]]) extends Command case class GetRefReply(ref: Option[ActorRef[OtherCommand]]) def initial(server: ActorRef[Server.Command]) = ContextAware[Command] { ctx => val adapter = ctx.spawnAdapter((got: Server.Got) => GotWrapper(got.id, got.contents)) behv(0, Map.empty)(adapter, server) } def behv(nextId: Int, replies: Map[Int, (String, ActorRef[GetRefReply])] )(implicit adapter: ActorRef[Server.Got], server: ActorRef[Server.Command]): Behavior[Command] = Total { case g @ GetRef(name) => server ! Server.Get(nextId)(adapter) behv(nextId + 1, replies.updated(nextId, name -> g.replyTo)) case GotWrapper(id, contents) => replies get id map (p => p._2 ! GetRefReply(contents get p._1)) behv(nextId, replies - id) } }
  • 31. The Implementation • independent add-on library • layered completely on top of untyped Actors • currently 2kLOC main + 1.7kLOC tests • fully interoperable 31
  • 32. The most important interface: Behavior[T] • Behaviors: • Full, FullTotal, Total, Partial, Static • Decorators: • ContextAware, SelfAware, SynchronousSelf, Tap • Combinators: • And, Or, Widened 32 abstract class Behavior[T] { def management(ctx: ActorContext[T], msg: Signal): Behavior[T] def message(ctx: ActorContext[T], msg: T): Behavior[T] def narrow[U <: T]: Behavior[U] = this.asInstanceOf[Behavior[U]] }
  • 33. ActorSystem ≈ ActorRef 33 object Demo extends App { implicit val t = Timeout(1.second) val guardian = ContextAware[Client.Command] { ctx => val server = ctx.spawn(Props(Server.initial), "server") val client = ctx.spawn(Props(Client.initial(server)), "client") Static { case msg => client ! msg } } val system = ActorSystem("Demo", Props(guardian)) import system.executionContext system ? Client.GetRef("X") map println foreach (_ => system.terminate()) }
  • 35. Behavior Rulez! • decoupling of logic from execution mechanism • synchronous behavioral tests of individual Actors • mock ActorContext allows inspection of effects 35
  • 36. 36 object `A Receptionist` { def `must register a service`(): Unit = { val ctx = new EffectfulActorContext("register", Props(behavior), system) val a = Inbox.sync[ServiceA]("a") val r = Inbox.sync[Registered[_]]("r") ctx.run(Register(ServiceKeyA, a.ref)(r.ref)) ctx.getAllEffects() should be(Effect.Watched(a.ref) :: Nil) r.receiveMsg() should be(Registered(ServiceKeyA, a.ref)) val q = Inbox.sync[Listing[ServiceA]]("q") ctx.run(Find(ServiceKeyA)(q.ref)) ctx.getAllEffects() should be(Nil) q.receiveMsg() should be(Listing(ServiceKeyA, Set(a.ref))) assertEmpty(a, r, q) } ... }
  • 37. What can we do with it?
  • 38. Encoding Types with Members 38 class MyClass { def myMethod(id: Int): String def otherMethod(name: String): Unit protected def helper(arg: Double): Unit }
  • 39. Encoding Types with Members • Typed Actors provide complete modules with members • Typed Actors can encode more flexible access privileges • more verbose due to syntax being optimized for classes 39 object MyClass { sealed trait AllCommand sealed trait Command extends AllCommand case class MyMethod(id: Int)(replyTo: ActorRef[String]) extends Command case class OtherMethod(name: String) extends Command case class Helper(arg: Double) extends AllCommand val behavior: Behavior[Command] = behavior(42).narrow private def behavior(x: Int): Behavior[AllCommand] = ??? }
  • 40. Calling Methods 40 object MyClassDemo { import MyClass._ val myClass: MyClass = ??? val myActor: ActorRef[Command] = ??? implicit val t: Timeout = ??? myClass.otherMethod("John") myActor!OtherMethod("John") val result = myClass.myMethod(42) val future = myActor?MyMethod(42) }
  • 41. But Actors can do more: Protocols 41 object Protocol { case class GetSession(replyTo: ActorRef[GetSessionResult]) sealed trait GetSessionResult case class ActiveSession(service: ActorRef[SessionCommand]) extends GetSessionResult with AuthenticateResult case class NewSession(auth: ActorRef[Authenticate]) extends GetSessionResult case class Authenticate(username: String, password: String, replyTo: ActorRef[AuthenticateResult]) sealed trait AuthenticateResult case object FailedSession extends AuthenticateResult trait SessionCommand }
  • 42. But Actors can do more: Protocols 42
  • 43. What can we express? • everything a classical module with methods can • pass object references as inputs and outputs • patterns beyond request–response • dynamic proxying / delegation 43
  • 44. What can we NOT express? • any dynamic behavior (e.g. internal state changes) • session invalidation 44
  • 46. Current Status • part of Akka 2.4-M1 • http://doc.akka.io/docs/akka/2.4-M1/scala/typed.html • only bare Actors • no persistence • no stash • no at-least-once delivery • no Java API yet (but taken into account already) 46
  • 47. Next Steps • proper Java API (probably in 2.4-M2) • Receptionist plus akka-distributed-data for Cluster • port Actor-based APIs to typed ones (e.g. Akka IO) • add FSM support with transition triggers • completely pure Actor implementation,
 «Actor Action Monad» (inspired by JoinCalculus) • listen to community feedback 47
  • 48. … and in the far future: • reap internal benefits by inverting implementation: • remove sender field (and thus Envelope) • make untyped Actor a DSL layer on top of Akka Typed • declare it non-experimental 48
  • 49. ©Typesafe 2015 – All Rights Reserved