Nachrichten


... [ Seminar Programmiersprachen und -Systeme ] ... [ Inhaltsverzeichnis ] ... [ receive oder react ] ...

Übersicht: Nachrichten


Was kann eine Nachricht sein?

Prinzipiell kann eine Nachricht vom Typ Any sein. Any ist die Wurzel der Scala Klassenhierarchie. Alle anderen Klassen in Scala erben also direkt oder indirekt von Any. Somit ist es also auch möglich, jeden Datentyp als Nachricht zu verschicken.
Für den empfangenden Actor ist es nur wichig, dass er den Typ einer Nachricht kennt. Sofern ihm der Typ bekannt ist, kann der Actor die Verarbeitung für diese Art von Nachricht ausführen.
Mögliche Nachrichten sind also zum einen Standardtypen wie Int, String oder Doubles, oder aber auch komplexe Datentypen, die man selbst definiert.


case classes

Besonders gut geeignet als Nachrichten sind die case classes. Sie sind im Grunde nichts anderes als normale aus Java bekannte Klassen mit einer beliebigen Anzahl von Feldern. Allerdings fügt der Scala Compiler automatisch einiges an Zusatzinformationen hinzu. So ist ein direkter lesender Zugriff auf die Felder möglich und es werden Funktionen wie toString(), equals() oder hashCode() automatisch generiert. Außerdem fügt der Compiler Informationen hinzu, die Pattern Matching erlauben.
Während in Java viele Zeilen benötigt werden, wird eine case class in Scala in nur einer simplen Zeile erstellt. Ein Beispiel für eine case class, die einen Namen mit Vor- und Nachnamen darstellt:

case class Name(nachName : String, vorName : String)  //Definition der case class Name
val name : Name("Simpson","Homer")                    //Erstellen eines Objekts mit Vor- und Nachname
println(name.nachName)                                //Ausgabe des Nachnamens

Eine solche Nachricht wäre also für einen Actor erkennbar. Es wäre ihm möglich, eine Reaktion auf diese Nachricht zu definieren und dementsprechend die Verarbeitung zu planen.


Verarbeiten von Nachrichten

Bekannt ist nun, wie eine Nachricht aussehen kann und wie sie verschickt wird. Nun muss der Actor also lernen, wie er Nachrichten aus seiner Mailbox holt und sie dann verarbeitet. Dazu dient die receive Methode, die innerhalb der bereits bekannten act Methode definiert wird. Sie geht die Mailbox durch und prüft jede Nachricht, ob eine Verarbeitung für ihren Typ möglich ist.

Ein Beispiel für einen Actor, der Nachrichten aus seiner Mailbox unabhängig von ihrem Typ verarbeitet:

val plapperActor = actor {
  while(true){
    receive {
      case "ende" =>
        exit()
      case nachricht =>
      println("Erhaltene Nachricht: " + nachricht)
    }
  }
}

//ein wenig Input für den plapperActor:

plapperActor ! "ein Text"
plapperActor ! 42
plapperActor ! Name("mouse", "mickey") //case class aus vorigem Beispiel
plapperActor ! "ende"


Erhaltene Nachricht: ein Text
Erhaltene Nachricht: 42
Erhaltene Nachricht: Name(mouse,mickey) //aus der automatisch generierten toString() Methode

Das Beispielprogramm


Der plapperActor kann also Nachrichten empfangen und diese nachplappern. Nun soll er aber auch noch Nachrichtentypen unterscheiden und abhängig von ihrem Typen eine Reaktion definieren.
Dazu ein weiteres Beispiel:

val schlauerPlapperActor = actor {
  while(true){
    receive {
      case text : String =>
        println("Nachricht mit Text: " + text)
      case zahl : Int =>
        println("Nachricht mit Zahl: " + zahl)
      case name : Name =>
        println("Nachricht mit Name: " + name)
      case ende : Ende =>
        println("schlauerPlapperActor beendet sich")
        exit()
      case undef =>
        println("Unbekannte Nachrichten plapper ich nicht nach!")
    }
  }
}

//ein wenig Input:

schlauerPlapperActor ! "ein Text"
schlauerPlapperActor ! 42
schlauerPlapperActor ! Name("mouse","mickey")
schlauerPlapperActor ! 1.3
schlauerPlapperActor ! Ende()


Nachricht mit Text: ein Text
Nachricht mit Zahl: 42
Nachricht mit Name: Name(mouse,mickey)
Unbekannte Nachrichten plapper ich nicht nach!
schlauerPlapperActor beendet sich

Das Beispielprogramm


An diesem Beispiel ist also schön erkennbar, dass der Actor in der Lage ist, die einzelnen Nachrichtentypen zu erkennen und dementsprechend auszugeben was für eine Nachricht er gerade bekommen hat.
Was passiert nun aber, wenn er eine Nachricht bekommt mit der er gar nichts anfangen kann? In diesem Beispiel werden auch unbekannte Nachrichten akzeptiert und einfach nicht nachgeplappert. Wenn nun aber solche undefinierten Nachrichten nicht akzeptiert werden, weiß der Actor nicht, was er mit der Nachricht anfangen soll. Durch die receive Methode werden die Nachrichten in der Mailbox auf ihren Typ überprüft. Dies geschieht mittels der Methode isDefinedAt(), die nur bestimmt, ob ein Nachrichtentyp bekannt ist oder nicht.
Falls eine Nachricht nicht bekannt ist, wird diese einfach in der Mailbox liegen gelassen und die nächste Nachricht wird geprüft. Den Actor behindert es also nicht, wenn er eine unbekannte Nachricht bekommt. Es kann sogar explizit erwünscht sein, daß eine Nachricht noch unbekannt ist, weil auch eine sequenzielle Nachrichtenverarbeitung möglich ist. Also der Nachrichtentyp eventuell erst später bekannt wird. Die sequenzielle Verarbeitung wird später noch beschrieben.


... [ Seminar Programmiersprachen und -Systeme ] ... [ Inhaltsverzeichnis ] ... [ receive oder react ] ...