开发者

How to restrict actor messages to specific types?

In Akka, is there a way to restrict messages to actors to be of a specific static type other than using the "Typed Actor" APIs that use an RPC style programming model?

Can I use the message passing style with Akka without throwing away static type safety at the actor boundaries?

For example, I'd like to use code like this:

sealed abs开发者_StackOverflow社区tract class FooMessage
case object Foo extends FooMessage
case object Bar extends FooMessage

class FooActor extends Actor[FooMessage] {
  def receive = {
    case Foo => () // OK

    // Would raise a compiler error:
    // case s: String => error("Can't happen, String is not a subtype of FooMessage") 

  }
}

val fooActor = actorOf[FooActor]
fooActor ! Foo // OK

// Won't compile:
fooActor ! "Hello"

Perhaps one would have to extend some base trait or have a construct like Either to allow for system level messages (Exit, etc.).


Then you'd have to encode the message type into the Actor ref, which would drastically decrease the value of something like the ActorRegistry.

Also, with powerful mechanics like "become" (which is fundamental to the actor model) typing the messages is less valuable.

Since Akka doesn't leak memory when a message is not matched to the current behavior, there is not the same risk of sending the "wrong" messages to the "wrong" actor.

Also, Actors are by nature dynamic, so if you want to make them static, use TypedActor (which is not RPC, it's just as RPC as regular actors, void methods are ! calls, Future return type is !!! and other return types are based on !!)

The common practice is to declare what messages an Actor can receive in the companion object of the Actor, which makes it very much easier to know what it can receive.

Does that help?


In Scala stdlib there was an excuse for making basic actors untyped (which is not applicable to Akka, because it doesn't support nested receives, as I remember). Lift, in its turn, supports typed actors out-of-the-box.

However, using channels, it's still possible to create strongly typed actors with stdlib:

object TypedActor {

  def apply[A](fun: PartialFunction[A, Any]): OutputChannel[A] = {
    val sink = new SyncVar[Channel[A]]
    actor {
      val in = new Channel[A](self)
      sink set in
      loop {
        in react { case any => reply(fun(any)) }
      }
    }
    sink.get
  }

}

sealed abstract class FooMessage
case object Foo extends FooMessage
case object Bar extends FooMessage

object Test {

  val fooActor = TypedActor[FooMessage]{
    case Foo => println("OK")
  }

  fooActor ! Foo 
  fooActor ! "Hello!" // doesn't compile -> Type mismatch; found: String("Hello!"); required: FooMessage;

}


Actually restricting an Actor to have only single type as input is not very useful. What is more useful to my mind is to list possible inputs in a strictly typed manner.

There is an approach for strictly typed inputs of actors (SynapseGrid):

case class Contact[T](...)
case class Signal[T](contact:Contact[T], data:T)

In your case the interface consists of a single input contact:

val FooInput = contact[FooMessage]("FooInput")

Within SynapseGrid framework handling of signals is defined with Builder:

class FooActorBuilder extends SystemBuilder {
  inputs(FooInput, OtherInput)
  FooInput.foreach(fooMessage => () //OK
  )
  OtherInput.foreach(...)
}

Obviously one cannot construct Signal with incompatible types. Thus we have compile time checking. In SynapseGrid there is a DSL for working with signals and contacts. For instance, to send Foo or Bar from outside:

val SomeOtherContact = contact[Boolean]("SomeOtherContact")
SomeOtherContact.map(flag => if(flag) Foo else Bar) >> FooInput

Of course one may simply send the message:

val inputMessage = Signal(FooInput, Foo)
actor ! inputMessage


It sounds like Akka's Akka's Typed Channel support was to have addressed this, but (according to the comment has already been removed from Akka in version 2.3).

In the documentation for Akka 2.2.3, there a good "design background" section that discusses the difficulties in support typed message sends and responses.

There's also a good NEScala talk by Roland Kuhn, Akka Typed Channels: Implementing Type Calculations as Macros ([YouTube] / [Slides]), that discusses the implementation of typed channels.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜