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.
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.