2
votes

Update: I've rewritten it in wonky-style and posted it on github - I would appreciate some feedback: https://github.com/drozzy/parallel-discrete-event-akka/tree/master/src/main/scala

Can anyone help me re-write "Parallel discrete event simulation" example from the "Chapter 32: Actors and Concurrency" from Programming in Scala, 2nd, by Martin Odersky?

It was written originally in Scala actors, but translating to Akka I encouter a lot of problems.

Some examples

Actor inheritance (p. 708)

Code like this:

trait Simulant extends Actor
class Wire extends Simulant

I have no idea how to translate to Akka, since in my understanding we never directly instantiate them.

Main Loop

The author constantly uses loops in actors, and I have no idea what they are about:

def act() {
    loop {
       if (running && busySimulants.isEmpty)
          advance()
       reactToOneMessage()
    }
}

Types

Mostly though, I am struggling with strong types -- it seems Akka, due to requiring ActorRefs prevents me from depending on a specific type of an actor. For example, in the book, the following:

trait Simulant extends Actor {
  val clock: Clock
  ...

depends on a strongly-typed actor Clock. And then it is simply "instantiated" in the implementing actor:

class Wire(name: String, init: Boolean) extends Simulant {
   def this(name: String) { this(name, false) }
   def this() { this("unnamed") }

   val clock = Circuit.this.clock

In my implementation I have something along the lines of:

trait Simulant extends Actor {
  val clock: ActorRef
  ...

and I have no idea how to "instantiate" it. What I have now (untested) is:

class Wire(val clock:ActorRef, name:String, init: Boolean) extends Actor{
  def this(clock:ActorRef, name:String) {this(clock, name, false)}
  def this(clock:ActorRef){this(clock, "unnamed")}

so I just end up draggin the actor refs around the constructors!

Hooking up components

How do I hook up components to each other? For example, hook-up an AndGate to a Wire - such that any time a signal on the wire changes it sends a message to the gate.

I do it by sending Add messages (i.e. AndGate sends Add to Wire so that wire can add it to the list of its subscribers), and so have to wait for all of them to arrive before starting the simulation. Is there any way to avoid that (the waiting)? (In original implementation the with Scala Actors, some actors were just accessed from global scope, and sometimes actors called other actor's methods directly!)

Source Code

The source code of the example can be found in full at the following url: http://booksites.artima.com/programming_in_scala_2ed/examples/html/ch32.html
under the heading:
32.6 A longer example: Parallel discrete event simulation

P.S.: I'm new to akka, so forgive my ignorance.

1

1 Answers

3
votes

I can not provide any migrated source code, but this link might help you: actors migration guide.

Some comments:

Actor Inheritance

You can do this in Akka, but class Wire has to implement the receive method.

Main Loop

In Akka you implement the receive method instead of the main loop.

Types

You can use an ActorRef as constructor parameter, but it has to be created (and started) before calling the constructor, e.g. with context.system.actorOf(...). And there is something called Typed Actors in Akka.

I also strongly encourage you to have a look at the documentation.

EDIT

I had a (quick) look at the source code, these are my findings:

  • In Scala it is not so common as in Java (and not enforced) that only one public class exists per file (although it can improve compile speed).
  • Demo.scala: Line 11, Use var instead of val
  • Constructor initialization (e.g. in FullAdder, Gate, ...): You should be careful about that, because the constructor is executed every time the actor is restarted; maybe using the preStart method would be better.
  • FullAdder, HalfAdder: An actor who doesn't react to messages (or only returning Unit) is a strange thing in my opinion. Maybe you find another solution for constructing an adder.
  • Clock.advance: Using return is not good scala style (and I believe it doesn't work in this case). Use else instead.