Question

I'm new to scala. When learning Actor, I tried to extend it to save one line of def:

import scala.actors.Actor
import Actor._
class Actoo(actoo: =>Unit) extends Actor {
    def act() {actoo}
}
object run extends Application {
    /* 
    // this one runs well
    val a = new Actor {
        def act() {
            receive { case 1 => println("1") }
        }
    }
    */
    val a = new Actoo {
        receive { case 1 => println("1") }
    }
    a.start
    a ! 1
}

Then the exception trace looks like this:

java.lang.AssertionError: assertion failed: receive from channel belonging to other actor
    at scala.Predef$.assert(Predef.scala:92)
    at scala.actors.Actor$class.receive(Actor.scala:424)
    at Actoo.receive(actoo.scala:3)
    at run$$anon$1.<init>(actoo.scala:16)
    at run$.<init>(actoo.scala:15)
    at run$.<clinit>(actoo.scala)
    at run.main(actoo.scala)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at scala.tools.nsc.ObjectRunner$$anonfun$run$1.apply(ObjectRunner.scala:75)
    at scala.tools.nsc.ObjectRunner$.withContextClassLoader(ObjectRunner.scala:49)
    at scala.tools.nsc.ObjectRunner$.run(ObjectRunner.scala:74)
    at scala.tools.nsc.MainGenericRunner$.main(MainGenericRunner.scala:154)
    at scala.tools.nsc.MainGenericRunner.main(MainGenericRunner.scala)

There may be many alternatives which can do the same thing, but it's better for me to know the reason why the code above doesn't work.

Was it helpful?

Solution

It's pretty easy. This behavior is not due to actors library, in fact. The piece of code

val a = new Actoo {
        receive { case 1 => println("1") }
    }

gets interpreted by a compiler as "create new instance of Actoo" with an initialization body receive {...} and val actoo becomes equal to (). Thus, your code is equivivalent to

val a = new Actoo() {
        receive { case 1 => println("1") }
    }

In order to fix the code, you need to write

val a = new Actoo ({
        receive { case 1 => println("1") }
    })

OTHER TIPS

There's also an actor method in the Actor singleton that does what you want. It even calls start for you automatically.

import scala.actors.Actor
import Actor._

val a = actor {
  receive { case 1 => println("1") }
}

a ! 1

Your are actually trying to receive from mailbox on the current native thread (native threads are Actors as well).

Witness the following:

Welcome to Scala version 2.7.5.final (Java HotSpot(TM) 64-Bit Server VM, Java 1.6.0_13).
Type in expressions to have them evaluated.
Type :help for more information.

scala> import scala.actors.Actor._
import scala.actors.Actor._

scala> self ! 123

scala> receive { case x => println(x) }
123

Now, what you want to accomplish is in the library already (Actor.actor):

val a = actor {
  receive { case x => println(x) }
}
// no need to start a 
a ! 123

BTW, it is a very bad idea to extend Application. Use def main(args: Array[String]) instead.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top