开发者

Scala maintaining state in actors without var

In another language, I have had something call itself with the new state to maintain it but I don't see how to do that with scala actors. Something like this is how I would envision this:

def act(state)
  react {
    case blah => act(doSomething(state, b开发者_如何学Clah))
  }
}


Well.. funny thing. I tweak my question a little and find it compiles. I realized that all that happens is that I have to return a partial function. Well I can return a partial function that has a parameter in there, so...

import scala.actors._

object MyActor extends Actor {
  def proc(s: Int) {
    react {
      case input: String =>
        if ((s % 10000) == 0) {
          println(s + ", " + input)
        }
        proc(s + 1)
    }
  }

  def act = proc(0)
}

object TestActors {
  def main(args: Array[String]): Unit = {
    MyActor.start()

    for (s <- 1 to 10000000) {
      MyActor ! "a message"
    }
  }
}

The nice thing is that with a little more tweaking, it could be generalized quite easily.


There are two other ways to store state in actors without using vars. If you only need to pass state forward, you can have the actor send a message to itself:

object MailsSelf {
  import scala.actors._
  class Selfish extends Reactor[Any] {
    def act() { loop { react {
      case i: Int if (i>=0) =>
        println(i)
        this ! (i-1)  // Self-messaging instead of recursive call
      case _ => exit
    }}}
  }
  def main(args: Array[String]) {
    (new Selfish).start() ! 5
  }
}

Alternatively, if you need to save state that is accessible during other messages, you can create another actor; whoever is calling you then needs to be informed about the new actor:

object EndlessActors {
  import scala.actors._
  class Delegater(n: Int) extends ReplyReactor {
    def act() { loop { react {
      case i: Int if (i*n >= 0) =>
        println(i*n)
        val next = new Delegater(n-1)
        next.start()
        reply(Some(next))
      case _ => reply(None); exit
    }}}
  }
  def main(args: Array[String]) {
    val original = new Delegater(5)
    original.start()
    Iterator.iterate( Option(original) ){ maybe =>
      maybe.flatMap(d => {
        val result = (d !? 5)
        result match {
          case Some(d2: Delegater) => Some(d2)
          case _ => None
        }
      })
    }.takeWhile(_.isDefined).foreach(_ => {})  // Foreach forces evaluation
  }
}

Personally, I think it's silly to do things this way. It's very inefficient (a new actor has to be created and an old one disposed of any time state changes--and actors are not that lightweight!), and it substantially complicates the code. It's more practical in most cases to keep your mutable state safely hidden as private[this] var within the actor, so that you know that only the actor itself may change its mutable state. Alternatively, you can reply not with a new actor but with state information that the caller is supposed to pass back, but this is slightly less safe since they could, in principle, modify the state information rather than just passing it back again.

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜