The fact that the current thread's call stack is discarded when an event-based actor suspends bears an important consequence on the event-based actor programming model: a call to react never returns normally. Instead, react always throws an internal control exception, which the actor runtime handles. Like any Scala or Java method, react could return normally only if its full call stack was available when it executed. Since that isn't the case with event-based actors, a call to react never returns.
The fact that react never returns means that no code can follow a react method invocation: Since react doesn't return, code following react would never execute. Thus, invoking react must always be the last thing an event-based actor does before it terminates. For example, in Listing 5.3 the actor won't print "finished" since it follows the call to react. This problem is corrected by moving the expression that prints "finished" into the body of the react call, as shown in Listing 5.4.
actor { react { case "hello" => println("hi") } println("finished") }
actor { react { case "hello" => println("hi") println("finished") } }
Since an actor's main job is to handle interesting messages, and since react defines an event-based message-handling mechanism for actors, you might think that react will always be the last, and even only, thing an actor needs to do. However, it is sometimes convenient to perform several react invocations in succession. In those situations, you could nest react invocations in sequence, as we saw in Listing 5.1.
Alternatively, you could define a recursive method that calls react several times in sequence. For instance, we can extend our simple chain example so that an actor waits for a specified number of 'Die messages before it terminates. Listing 5.5 shows how to do this by replacing the body of the chain actors with a call to the waitFor method. The waitFor method tests up front whether the current actor should terminate (if n == 0) or continue waiting for messages. The protocol logic is the same as before. The only difference is that after each message sends to from, we added a recursive call to waitFor.
def waitFor(n: Int): Unit = if (n > 0) { react { case 'Die => val from = sender if (next != null) { next ! 'Die react { case 'Ack => from ! 'Ack; waitFor(n - 1) } } else { from ! 'Ack; waitFor(n - 1) } } }