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

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsArshad QA
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendArshad QA
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVshikhaohhpro
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AIABDERRAOUF MEHENNI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdfWave PLM
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerThousandEyes
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsJhone kinadey
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...gurkirankumar98700
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...OnePlan Solutions
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...panagenda
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️anilsa9823
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsAndolasoft Inc
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsAlberto González Trastoy
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...OnePlan Solutions
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfkalichargn70th171
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxbodapatigopi8531
 
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
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionSolGuruz
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Modelsaagamshah0812
 

Recently uploaded (20)

Software Quality Assurance Interview Questions
Software Quality Assurance Interview QuestionsSoftware Quality Assurance Interview Questions
Software Quality Assurance Interview Questions
 
Test Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and BackendTest Automation Strategy for Frontend and Backend
Test Automation Strategy for Frontend and Backend
 
Optimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTVOptimizing AI for immediate response in Smart CCTV
Optimizing AI for immediate response in Smart CCTV
 
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AISyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
SyndBuddy AI 2k Review 2024: Revolutionizing Content Syndication with AI
 
5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf5 Signs You Need a Fashion PLM Software.pdf
5 Signs You Need a Fashion PLM Software.pdf
 
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected WorkerHow To Troubleshoot Collaboration Apps for the Modern Connected Worker
How To Troubleshoot Collaboration Apps for the Modern Connected Worker
 
Right Money Management App For Your Financial Goals
Right Money Management App For Your Financial GoalsRight Money Management App For Your Financial Goals
Right Money Management App For Your Financial Goals
 
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
(Genuine) Escort Service Lucknow | Starting ₹,5K To @25k with A/C 🧑🏽‍❤️‍🧑🏻 89...
 
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
Tech Tuesday-Harness the Power of Effective Resource Planning with OnePlan’s ...
 
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
W01_panagenda_Navigating-the-Future-with-The-Hitchhikers-Guide-to-Notes-and-D...
 
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online  ☂️
CALL ON ➥8923113531 🔝Call Girls Kakori Lucknow best sexual service Online ☂️
 
How To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.jsHow To Use Server-Side Rendering with Nuxt.js
How To Use Server-Side Rendering with Nuxt.js
 
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...
 
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time ApplicationsUnveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
Unveiling the Tech Salsa of LAMs with Janus in Real-Time Applications
 
Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...Advancing Engineering with AI through the Next Generation of Strategic Projec...
Advancing Engineering with AI through the Next Generation of Strategic Projec...
 
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdfThe Ultimate Test Automation Guide_ Best Practices and Tips.pdf
The Ultimate Test Automation Guide_ Best Practices and Tips.pdf
 
Hand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptxHand gesture recognition PROJECT PPT.pptx
Hand gesture recognition PROJECT PPT.pptx
 
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...
 
Diamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with PrecisionDiamond Application Development Crafting Solutions with Precision
Diamond Application Development Crafting Solutions with Precision
 
Unlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language ModelsUnlocking the Future of AI Agents with Large Language Models
Unlocking the Future of AI Agents with Large Language Models
 

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