I am an experienced Java programmer and I am starting to develop actor-based Scala applications. In the application that I am currently developing, I have to deal with the implementation of the role of the Sender, exhibiting both autonomous and reactive behavior. The scenario is as follows (pseudo-code):
Actor Sender{ Active behavior (must be active once the actor boots): do-in-sequence{ send to Stdout A send to Stdout B send to Stdout C send stop to Stdout and then exit } Reactive behavior (must be active once the actor boots): as soon as received stop from StopNotifier -> send stop to Stdout and then exit } } Actor Stdout{ Purely reactive behavior (ie wait for msg){ as soon as received A -> print A as soon as received B -> print B as soon as received C -> print C as soon as received stop from Sender -> exit } } Actor StopNotifier Purely active behavior { compute, and when some condition is met -> send stop to Sender }
My question is: is this the best way to express autonomous behavior for a Scala actor who needs to integrate autonomy and reactivity (as described in this article )?
In other words, what is the best way / style to encode the Sender actor in the above example?
I came up with a solution (see below), but since I am not a Scala guru (for now :) :), I would like to know if it is possible to improve what I implemented in an improved / improved solution.
case object START case object A case object B case object C case object SENT_A case object SENT_B case object ACK_A case object ACK_B case object ACK_C case object STOP class Sender(stdout: Stdout) extends Actor { def act() { self!START while (true){ receive { case START => stdout!?A self!SENT_A case SENT_A => stdout!?B self!SENT_B case SENT_B => stdout!?C stdout!?STOP exit() case STOP => { Console.println("[Sender:]Received STOP, terminating") stdout!?STOP exit() } } } } } class Stdout() extends Actor { def act() { while (true) { receive{ case A => Console.println("[Stdout:]A") reply(ACK_A) case B => Console.println("[Stdout:]B") reply(ACK_B) case C => Console.println("[Stdout:]C") reply(ACK_C) exit() case STOP => Console.println("[Stdout:]Received STOP, terminating") exit() } } } } class StopNotifier(sender: Sender) extends Actor { def act() { Thread.sleep(200) Console.println("[StopNotifier:]Sending STOP to sender") sender ! STOP exit() } } object app extends Application { val stdout = new Stdout stdout.start val sender = new Sender(stdout) sender.start val stopNotifier = new StopNotifier(sender) stopNotifier.start }
In particular, what bothers me in my current implementation is that in order to quickly respond to receiving a STOP message from StopNotifier, I had to send messages at each stage of the Senderβs execution (i.e., after sending A, B to the actor Stdout). It seems too complicated to be the right way to do things :).
I also tried to develop another solution using other Scala language conventions (e.g. asynchronous sending, reaction, etc.), but somehow they seemed to me affected by other problems / tricks.
Does anyone have a better solution to combat the integration of autonomy and reactive behavior in Scala actors?