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

chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptkotipi9215
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyFrank van der Linden
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxTier1 app
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackVICTOR MAESTRE RAMIREZ
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Andreas Granig
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software DevelopersVinodh Ram
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmSujith Sukumaran
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...kellynguyen01
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...aditisharan08
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataBradBedford3
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number SystemsJheuzeDellosa
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantAxelRicardoTrocheRiq
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...soniya singh
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationkaushalgiri8080
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...MyIntelliSource, Inc.
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningVitsRangannavar
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样umasea
 
buds n tech IT solutions
buds n  tech IT                solutionsbuds n  tech IT                solutions
buds n tech IT solutionsmonugehlot87
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEOrtus Solutions, Corp
 

Recently uploaded (20)

chapter--4-software-project-planning.ppt
chapter--4-software-project-planning.pptchapter--4-software-project-planning.ppt
chapter--4-software-project-planning.ppt
 
Engage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The UglyEngage Usergroup 2024 - The Good The Bad_The Ugly
Engage Usergroup 2024 - The Good The Bad_The Ugly
 
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptxKnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
KnowAPIs-UnknownPerf-jaxMainz-2024 (1).pptx
 
Cloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStackCloud Management Software Platforms: OpenStack
Cloud Management Software Platforms: OpenStack
 
Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024Automate your Kamailio Test Calls - Kamailio World 2024
Automate your Kamailio Test Calls - Kamailio World 2024
 
Professional Resume Template for Software Developers
Professional Resume Template for Software DevelopersProfessional Resume Template for Software Developers
Professional Resume Template for Software Developers
 
Intelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalmIntelligent Home Wi-Fi Solutions | ThinkPalm
Intelligent Home Wi-Fi Solutions | ThinkPalm
 
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
Short Story: Unveiling the Reasoning Abilities of Large Language Models by Ke...
 
Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...Unit 1.1 Excite Part 1, class 9, cbse...
Unit 1.1 Excite Part 1, class 9, cbse...
 
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer DataAdobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
Adobe Marketo Engage Deep Dives: Using Webhooks to Transfer Data
 
What is Binary Language? Computer Number Systems
What is Binary Language?  Computer Number SystemsWhat is Binary Language?  Computer Number Systems
What is Binary Language? Computer Number Systems
 
Salesforce Certified Field Service Consultant
Salesforce Certified Field Service ConsultantSalesforce Certified Field Service Consultant
Salesforce Certified Field Service Consultant
 
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
Russian Call Girls in Karol Bagh Aasnvi ➡️ 8264348440 💋📞 Independent Escort S...
 
Project Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanationProject Based Learning (A.I).pptx detail explanation
Project Based Learning (A.I).pptx detail explanation
 
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
Steps To Getting Up And Running Quickly With MyTimeClock Employee Scheduling ...
 
cybersecurity notes for mca students for learning
cybersecurity notes for mca students for learningcybersecurity notes for mca students for learning
cybersecurity notes for mca students for learning
 
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
办理学位证(UQ文凭证书)昆士兰大学毕业证成绩单原版一模一样
 
buds n tech IT solutions
buds n  tech IT                solutionsbuds n  tech IT                solutions
buds n tech IT solutions
 
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASEBATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
BATTLEFIELD ORM: TIPS, TACTICS AND STRATEGIES FOR CONQUERING YOUR DATABASE
 
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...Call Girls In Mukherjee Nagar 📱  9999965857  🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
Call Girls In Mukherjee Nagar 📱 9999965857 🤩 Delhi 🫦 HOT AND SEXY VVIP 🍎 SE...
 

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