Unsafe Usage
We will reuse the definitions and actors from the « Basic Usage.
scala> val typedRef = ActorOf[MyMessage](props, name = "my-actor")
typedRef: de.knutwalker.akka.typed.ActorRef[MyMessage] = Actor[akka://foo/user/my-actor#-43504562]
Autoreceived Messages
Some messages are automatically handled by some actors and need or cannot be provided in the actors type.
One example is PoisonPill
. To sent those kind of messages anyway, use unsafeTell
.
scala> typedRef.unsafeTell(PoisonPill)
Switch Between Typed and Untyped
Also, some Akka APIs require you to pass an untyped ActorRef (the regular ActorRef).
You can easily turn your typed actor into an untyped one bu using untyped
.
scala> val untypedRef = typedRef.untyped
untypedRef: de.knutwalker.akka.typed.package.UntypedActorRef = Actor[akka://foo/user/my-actor#-43504562]
For convenience, akka.actor.ActorRef
is type aliased as de.knutwalker.akka.typed.UntypedActorRef
.
Similarly, you can turn any untyped ref into a typed one using typed
.
scala> val typedAgain = untypedRef.typed[MyMessage]
typedAgain: de.knutwalker.akka.typed.package.ActorRef[MyMessage] = Actor[akka://foo/user/my-actor#-43504562]
As scala tends to infer Nothing
as the most specific bottom type, you want to make sure to always provide a useful type.
scala> untypedRef.typed
res1: de.knutwalker.akka.typed.package.ActorRef[Nothing] = Actor[akka://foo/user/my-actor#-43504562]
Compiletime only
There are no compiler checks to make sure, that the given actually is able to receive that kind of message.
This signifies the point, that Typed Actors are really just a compile-time wrapper and do not carry any kind of runtime information.
To further demonstrate this, you can see that both instances are actually the very same (despite the scalac warning).
scala> typedRef eq untypedRef
<console>:29: warning: AnyRef{type Message = MyMessage; type Self = de.knutwalker.akka.typed.UntypedActorRef} and akka.actor.ActorRef are unrelated: they will most likely never compare equal
typedRef eq untypedRef
^
res2: Boolean = true
Divergence
This also means, that it is possible to diverge from the specified type with context.become
.
scala> class MyOtherActor extends Actor {
| def receive = LoggingReceive {
| case Foo(foo) => println(s"received a Foo: $foo")
| case Bar(bar) => context become LoggingReceive {
| case SomeOtherMessage => println("received some other message")
| }
| }
| }
defined class MyOtherActor
scala> val otherRef = ActorOf(Props[MyMessage, MyOtherActor], "my-other-actor")
otherRef: de.knutwalker.akka.typed.package.ActorRef[MyMessage] = Actor[akka://foo/user/my-other-actor#-1084758492]
scala> otherRef ! Foo("foo")
[DEBUG] received handled message Foo(foo)
received a Foo: foo
scala> otherRef ! Bar("bar")
[DEBUG] received handled message Bar(bar)
scala> otherRef ! Foo("baz")
[DEBUG] received unhandled message Foo(baz)
scala> otherRef.untyped ! SomeOtherMessage
[DEBUG] received handled message SomeOtherMessage
received some other message
Making sure, that this cannot happen is outside of the scope of Typed Actors.
There is, however, a TypedActor
trait which tries to provide some help. Learn about it next.