- About Scala
- Documentation
- Code Examples
- Software
- Scala Developers
Actors "link" Help
Tue, 2010-02-23, 18:40
Actors "link" Help
Here’s a very simple program I am working on to try to understand actor linking. If I understand correctly, once I link the actors, a message sent to one will be forwarded to the other, but there’s no documentation on this, so I am totally guessing. I’ve created the attached spike solution in an attempt to create some sort of interesting behavior, but nothing noticeable seems to happen.
I would expect that once I do the link, messages I send to actor1 would also be sent to listener. Is that correct? If not, what is the right behavior? I am using 2.7.7 final.
Thanks,
Mark
package spikes
import scala.actors._
import scala.actors.Actor._
object ActorLinking {
def main(args : Array[String]) : Unit = {
println("Exploring actor linking")
actor1 ! "Pre link"
listener ! "Pre link"
actor1 ! Listen(listener)
actor1 ! "Post link"
listener ! "Post link"
actor1 ! 'exit
println("I don't get it")
}
case class Listen(actor : Actor)
val actor1 : Actor = actor {
loop {
react {
case Listen(x) => link(x)
case 'exit => exit
case x => println("actor1: " + x)
}
}
}
val listener = actor {
loop {
react {
case 'exit => exit
case x => println("listener: " + x)
}
}
}
}
I would expect that once I do the link, messages I send to actor1 would also be sent to listener. Is that correct? If not, what is the right behavior? I am using 2.7.7 final.
Thanks,
Mark
package spikes
import scala.actors._
import scala.actors.Actor._
object ActorLinking {
def main(args : Array[String]) : Unit = {
println("Exploring actor linking")
actor1 ! "Pre link"
listener ! "Pre link"
actor1 ! Listen(listener)
actor1 ! "Post link"
listener ! "Post link"
actor1 ! 'exit
println("I don't get it")
}
case class Listen(actor : Actor)
val actor1 : Actor = actor {
loop {
react {
case Listen(x) => link(x)
case 'exit => exit
case x => println("actor1: " + x)
}
}
}
val listener = actor {
loop {
react {
case 'exit => exit
case x => println("listener: " + x)
}
}
}
}
Consider the following example:
val divide = actor {
// The other half of error handling
self.trapExit = true
def newLinkedWorker = {
val worker = actor { loop { react {
case (x: Int, y: Int) => println(x + " / " + y + " = " + (x / y))
}}}
self link worker
worker
}
// Message handler loop
def run(worker: Actor): Nothing = react {
case (x: Int, y: Int) =>
worker ! (x, y)
run(worker)
case Exit(deadWorker, reason) =>
println("Worker died because of: " + reason)
run(newLinkedWorker)
}
run(newLinkedWorker)
}
In this contrived example, the actor divide takes a tuple of integers and prints the result of dividing them. It does so by creating another actor to do the actual work. These two actors are linked, and the main actor traps exits. Linking means that when either one of them dies, one of two things will happen: if the linked actor traps exits, it will receive a message indicating who died and why; if the linked actor does not trap exits, it will die too (which will be propagated to other actors linked to it, etc, etc).
In the example above, if you send call divide ! (1, 0) the worker actor dies due to divide-by-zero. The main actor is notified, replaces it's worker with a new linked actor, and happily continues to serve other clients who are looking to divide more sensible numbers.
If you're looking for more information on the subject, some very good information can be found in Joe Armstrong's erlang book from Pragmatic Programmers. The chapters on error handling do a good job of introducing these and related concepts (obviously, in erlang, but the concepts map almost directly to scala).
- Colin