Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
Teil III - Referenz

5 Die Tango-Beschreibungssprache

Dieses Kapitel enthält alle Sprachelemente der Tango-Beschreibungssprache. Die Elemente sind thematisch gegliedert, so dass ein gesamter Themenbereich fortlaufend gelesen werden kann. Zu jedem Sprachelement werden Verweise in die vorangegangenen Kapitel angeboten, wenn dieses Sprachelement dort aus prinzipieller Sicht bereits erläutert wurde.

Die nachfolgende Übersichtstabelle erlaubt den Quereinstieg mit Stichworten oder Symbolen. Diese Tabelle enthält sämtliche Sprachelemente von Tango.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

5.1 Übersicht über alle Sprachelemente

  A
  absoluter Pfad
@ Aktion
=> Aktivitätsblock
+ Aktivator
{ } allgemeine formlose Beschreibung
++ Alias
  Aspekt
. Aufzählung
[ | ] Auswahlliste
[ || ] Auswahlliste, strenge
  B
 & Bedingung
  Bedingungskaskade
  Bereich
  Block
C
# Container
D
!! Datei einbinden
  Datenstruktur
! Definitionsblock
E
§ Eigenschaft
  Einrücken
... Ellipse
* Ereignis
F
Filter
formlose Beschreibung
{ } formlose Beschreibung, allgemeine
" " formlose Wertbeschreibung
G
--- geordnete Liste
I
!! Include-Datei
: Inhaltsbeschreibung
<- Interpretation
K
Kanal
// Kommentar
Konstante
Kontext
Kopfaspekt
L
  Leerzeichen
  Leerzeile
... Liste
--- Liste, geordnet
M
Markierung
( , ) Mehrfachaspekt
N
Name
O
ODER-Verknüpfung
P
Pfad
  Pfad, absoluter
  Pfad, relativer
= Prüfalternative
R
  relativer Pfad
^ Rückgabewert
S
% Schema
<< Senden
- Sequenz
Spezialisierungsprefix
[ || ] strenge Auswahlliste
T
Teile-Beziehung
terminaler Aspekt
_ Typ
U
&& UND-Verknüpfung
ungeordnete Liste
Unteraspekt
Unteraspektblock
Unterblock
V
Verfeinerung
<- Verweis
? = = Verzweigung
W
Wert
Wertlieferant
:= Wertzuweisung
Wirkung
=> Wirkungspfeil
Z
  Zeilenumbruch
$ Zustand
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

5.2 Aspekte beschreiben und referenzieren

Eine Tango-Spezifikation ist eine Sammlung von Aussagen (Aspekten), die mit den Mitteln der Tango-Beschreibungssprache geordnet und in Bezug zueinander gesetzt werden.

Ein formlos beschriebener Aspekt muss nur minimalen formalen Anforderungen genügen. Damit kann beliebige Information in eine Tango-Spezifikation integriert werden, z.B. auch grafische Darstellungen oder Audiodateien. Die Möglichkeiten, Aspekte zu beschreiben sind eher durch die Bearbeitungswerkzeuge begrenzt als durch die Tango-Beschreibungssprache.

Aspekte können nach Kriterien der Tango-Beschreibungsmethodik oder der Domäne in Kategorien eingeordnet werden mit Markierungen und Spezialisierungsprefixen. Aspekte werden nach ihrer Funktion im Produkt in Blöcke oder Listen zusammengefasst. Die Teile-Beziehung erlaubt, Aspekte mit anderen Aspekten zu beschreiben. Zusammenhänge im Produkt werden durch Referenzen von Aspekten auf andere Aspekte notiert.

Der Detaillierungsgrad der Spezifikation ist frei wählbar, die Grenze der Beschreibung wird durch terminale Aspekte und Ellipsen angezeigt.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Aspekt

Siehe auch: Konzepte

Aspekte sind die grundlegende Beschreibungseinheit der Tango-Spezifikation. Sie beschreiben Elemente, Eigenschaften oder Wirkungen des Produkts. Eine detaillierte Darstellung von Aspekten findet sich im Kapitel 4.2. Jede Aussage über das Produkt ist ein Aspekt, deshalb kann Aspekten keine spezifische Syntax zugeordnet werden. Mit einer Teile-Beziehung werden Aspekte durch andere Aspekte, genannt Unteraspekte, näher beschrieben.

Aspekte können Meta-Aussagen oder organisatorische Information enthalten, die sich nicht direkt auf das Produkt beziehen, sondern auf die Tango-Spezifikation selbst oder den Projektablauf. So sind z.B. Verweise auf Zeichnungen möglich, ebenso Änderungshinweise, Testanweisungen, oder das Einbinden von Dateien, die Teile der Spezifikation enthalten. Eine Tango-Spezifikation ermöglicht damit den Bezug auf alle produktrelevanten Informationsquellen. Das Integrieren neuer Erkenntnisse über das Produkt kann in der Spezifikation vorbereitet werden, noch bevor die Änderungen tatsächlich durchgeführt werden.

Die Beschreibung eines Aspekts kann formlos erfolgen, sie unterliegt keinen tangospezifischen Vorgaben außer der einen, dass das Ende der Beschreibung erkennbar sein muss. Wenn ein Aspekt mit einem Namen versehen wird, erhält er dadurch eine Identität und kann von anderen Stellen der Spezifikation aus referenziert werden. Dies ist nützlich, wenn der Aspekt einen Zustand beschreibt, dessen Wert irgendwo zur weiteren Bearbeitung benötigt wird. Namen sind nicht nur Ankerpunkte für eine Referenz, sie dienen in erster Linie der Beschreibung des Aspekts, deshalb werden Namen von Aspekten aussagekräftig gewählt.

Aspekte beschreiben Eigenschaften des Produkts. Diese Eigenschaften können in Kategorien eingeordnet werden. Durch Kennzeichnung der Aspekte gemäß ihrer Kategorien kann der Aufwand zur Beschreibung der Aspekte reduziert werden, denn die Eigenschaften der Kategorie müssen nicht bei jedem Aspekt gesondert beschrieben werden. Aspekte, die einer Kategorie zugeordnet werden, können durch einen Spezialisierungsprefix oder durch Markierungen gekennzeichnet werden.

Aspekte müssen nicht explizit definiert werden, sie sind bekannt, sobald sie verwendet werden. Sie können implizit entstehen bei der Beschreibung eines anderen Aspekts, wie im folgenden Ausschnitt aus dem Beispiel Anmeldedialog:

!$LoginDaten
    .UserListe
        ...User
            .ZugangErlaubt : [ KannArbeiten | Gesperrt ]
            ...
 

ZugangErlaubt ist ein Zustand, der Teil jedes Eintrags in der UserListe ist. Neben dem Unteraspekt ZugangErlaubt werden in der Auswahlliste als weitere Aspekte die Werte KannArbeiten und Gesperrt definiert, die dieser Zustand annehmen kann.

Die Konsistenz der Beschreibung in einer Tango-Spezifikation kann im Rahmen des frei wählbaren Detaillierungsgrades geprüft werden. Durch terminale Aspekte und Ellipsen wird die Grenze der Detaillierung festgelegt.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Allgemeine formlose Beschreibung

Siehe auch: Sprachelemente

Ein Aspekt kann formlos beschrieben werden. Diese Beschreibung unterliegt keinerlei tangospezifischen Randbedingungen außer der einen, dass das Ende der Beschreibung identifizierbar sein muss. Die allgemeine formlose Beschreibung ist in geschweifte Klammern gesetzt, und die einzige Forderung an den Inhalt ist, dass jede öffnende geschweifte Klammer auch wieder geschlossen werden muss. Im Beispiel Anmeldedialog findet sich folgende formlose Beschreibung:

            .{während der Eingabe ein Sternchen pro eingetipptem 
              Zeichen an TxAnzeige anhängen}

Wenn sich die Beschreibung über mehrere Zeilen erstreckt, dann ist übliche Praxis, dass die öffnende Klammer das am weitesten links stehend Zeichen des beschreibenden Textblocks ist. Diese Konvention ist ohne Auswirkung auf die Bedeutung der formlosen Beschreibung.

Eine formlose Beschreibung wird als Terminal betrachtet, d.h. eine weitere Verfeinerung dieses Aspekts ist nicht notwendig. Dies verbietet aber nicht, dass der Aspekt trotzdem weiter verfeinert wird.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Formlose Wertbeschreibung "  "

Siehe auch: Sprachelemente

Für die Beschreibung von Werten oder Information wird die formlose Wertbeschreibung verwendet. Eine formlose Wertbeschreibung wird zwischen Gänsefüßchen gesetzt. Der Inhalt ist beliebig mit der Einschränkung, dass im beschreibenden Text keine Gänsefüßchen verwendet werden dürfen.

Jede formlose Wertbeschreibung kann durch eine allgemeine formlose Beschreibung ersetzt werden, deshalb wird oft von formloser Beschreibung gesprochen, wenn beide Notationen möglich sind. Umgekehrt kann nicht jede allgemeine formlose Beschreibung durch eine formlose Wertbeschreibung ersetzt werden, denn außer Werten können auch andere Eigenschaften beschrieben sein, z.B. Wirkungen oder Elemente.

Die formlose Wertbeschreibung enthält die Bedeutung des Wertes, nicht den Wert selbst. Eine aussagekräftige Beschreibung "Ja, Speichern erfolgreich" ist einem einfachen "Ja" immer vorzuziehen. Ein Leerstring "" bedeutet nicht notwendigerweise einen leeren String als Wert, mögliche Werte wären auch unbesetzt, NULL oder der String "- bitte auswählen -". Die genaue Interpretation einer formlosen Wertbeschreibung wird durch die Domäne vorgegeben.

     "Integer 23"                 // die Beschreibung einer Integer-Zahl
     "23"                         // irgendeine Zahl mit dem Wert 23, vielleicht auch Real, Complex...
     "Zufallszahl 1 bis 6"        // das Domänenwissen sagt, dass hier gewürfelt wird.
     "selektierter Name"          // beschreibt die Herkunft des Wertes
     "2 * $EtEingabefeld"         // ein berechneter Wert
     "falsche Eingabe"            // eine Meldung, dies ist nur der Sinn, nicht der Meldetext selbst
     "Ja, akzeptiert"             // ein logischer Wert mit Erklärung, was er bedeutet

Die formlose Wertbeschreibung wird auch genutzt, um domänenspezifische Transformationen zu beschreiben, insbesondere mathematische Berechnungen. Die Tango-Beschreibungssprache enthält dazu keine eigenen Beschreibungshilfsmittel. In der formlosen Wertbeschreibung kann auf Aspekte der Spezifikation Bezug genommen werden, in den Beispielen oben auf den Zustand von EtEingabefeld oder einen irgendwo selektierten Namen.

Zahlen können in der Spezifikation mit oder ohne Gänsefüßchen geschrieben werden. Ohne Gänsefüßchen sind sie Namen und unterliegen den entsprechenden Konventionen, die für Namen gelten, sie müssen eindeutig sein und dürfen keinen Punkt enthalten. Diese Probleme werden umgangen, wenn Zahlen als formlose Wertbeschreibung in Gänsefüßchen niedergeschrieben werden.

Eine formlose Wertbeschreibung wird als Terminal betrachtet, weil sie grundsätzlich die gesamte beschreibende Information zu einem Wert enthalten kann. Sie kann bei Bedarf trotzdem durch Unteraspekte weiter verfeinert werden.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Name

Siehe auch: Sprachelemente

Namen kennzeichnen und beschreiben einen Aspekt. Sie geben einem Aspekt eine Identität, so dass der Aspekt nicht nur über seine Eigenschaften, sondern auch direkt referenziert werden kann.

Die Syntax von Namen ist nur wenig beschränkt, Namen müssen lediglich von Konstrukten der Tango-Beschreibungssprache unterscheidbar sein. Ein Name darf keine Leerzeichen und keinen Punkt enthalten. Andere Sonderzeichen können verwendet werden, solange erkennbar bleibt, dass es sich hier um einen Namen handelt. Namen sollten durch Leerzeichen von Symbolen der Tango-Beschreibungssprache getrennt werden, damit ein Konstrukt nicht irrtümllich als Name interpretiert werden kann.

Markierungssymbole in führender Position werden immer als Markierungen interpretiert und nicht als Teil des Namens. Markierungen sind kein Bestandteil des Namens, sie können jederzeit weggelassen werden und sind nicht distinktiv. Spezialisierungsprefixe sind Bestandteil des Namens und deshalb distinktiv.

Führende Sonderzeichen werden, wenn möglich, als Teil eines Konstrukts der Tango-Beschreibungssprache interpretiert und nicht als Teil des Namens. Dies gilt z.B. für ? als Beginn der Verzweigung, & als Bedingung, oder = als Kennzeichnung einer Alternativenzeile in einer Verzweigung. Sonderzeichen in einem Namen sind möglich, sie markieren deshalb kein Namensende.

Groß- und Kleinschreibung in Namen ist distinktiv.

Zahlen können als Name niedergeschrieben werden. Eine Zahl allein als Name bietet sich an, wenn nur der Wert selbst interessiert 1). Aspekte mit einer Zahl als Name dürfen nicht verfeinert werden. Soll eine Zahl genauer spezifiziert werden, so kann dies im Namen direkt erfolgen: SmallInteger212, Zufallszahl<12. Alternativ kann die formlose Wertbeschreibung verwendet werden, um Zahlen genauer zu beschreiben.

!#Namensbeispiele
    .EtDatum                     // Name mit Spezialisierungsprefix  
    .Tx#Merker                   // Sonderzeichen mitten im Namen ist ok
    .+BtTuwas                    // Name ist BtTuwas, die Markierung gehört nicht zum Namen
        =>  .& WasserKalt &      // ist gut so, WasserKalt& würde als Name interpretiert
                &SpätAbends      // & wird aus dem Kontext erkannt, besser wäre & SpätAbends
                    =>  .@irgendwasTun                  // @ irgendwasTun wäre ebenso ok.
                        .Tx#Merker := Zufallszahl<12    // OK, rechts steht ein korrekter Name
                        .tuDasNicht:=123                // ??? der ganze Aspekt ist ein Name, keine Wertzuweisung
                        .zwanzig := 20                  // OK, korrekte Wertzuweisung
    .HalloText
    .$HalloText                  // FEHLER: Markierung davor ist nicht distinktiv, den Namen gibt es schon
    .TxDatum                     // OK, kollidiert nicht mit EtDatum, anderer Spezialisierungsprefix
    .TxDATUM                     // OK, Großschreibung ist distinktiv

Die Namenssyntax ist so wenig wie möglich beschränkt, damit eine Anpassung der Tango-Beschreibung an verschiedene Aufgabenbereiche möglich ist. Trotz dieser lockeren Vorgaben wird von der exzessiven Nutzung von Sonderzeichen abgeraten in Hinblick auf eine maschinelle Verarbeitung der Spezifikation.

Ein Name muss so gewählt sein, dass er in der vorgesehenen Verwendung eindeutig ist. Zwei Unteraspekte eines Aspekts können nicht den gleichen Namen haben, d.h. ein Name kann in einem Unterblock nur einmal zur Bezeichnung eines Aspekts verwendet werden. Andernfalls wäre ein Pfad mit diesem Namen nicht mehr eindeutig, die Spezifikation ist fehlerhaft. Die Namen der Kopfaspekte jedes Definitionsblocks in einer Datei müssen ebenfalls eindeutig sein.

In einem Kontext können Namen für Aspekte gleich sein, solange sie nicht im selben Unterblock niedergeschrieben sind. Die Spezifikation wird nicht fehlerhaft, solange diese gleich benannten Aspekte mit einem eindeutigen Pfad oder überhaupt nicht referenziert werden. Das folgende Beispiel verwendet Namen korrekt:

!WnBetriebsstatus
    .LpHauptenergie : [ Ein | Aus ]            // Anzeige durch Lampe, Lp___      
    .LpLinkeDüse : [ Auf | Zu ]
    .LpRechteDüse : [ Auf | Zu ]
    .Reservezweig
        .LpLinkeDüse : [ Auf | Zu ]
        .LpRechteDüse : [Auf | Zu ]
        .LpSpülen : [ Ein | Aus ]
    .+BtPrüfen
        =>  ...

Der Kontext in diesem Beispiel wird vom Definitionsblock gebildet. In diesem Kontext werden viele Namen mehrfach verwendet: LpLinkeDüse, LpRechteDüse, Auf, Zu, Ein, Aus. Keiner dieser Namen wird im selben Unterblock zweimal definiert, deshalb ist die Spezifikation korrekt. Sie könnte fehlerhaft werden, wenn im Aktivitätsblock von BtPrüfen diese Namen uneindeutig verwendet werden:

    .+BtPrüfen
        =>  .LpRechteDüse := Auf                 // Fehler: welches LpRechteDüse ist gemeint?
            .Reservezweig.LpRechteDüse := Auf    // OK
            .LpSpülen := Aus                     // OK, eindeutig 

Der Aspekt Aus wäre prinzipiell ebenfalls mehrdeutig, aber die Wertzuweisung erzwingt, dass der Wert WnBetriebsstatus.Reservezweig.LpSpülen.Aus gemeint ist.

Namen bieten zusammen mit Markierungen und Spezialisierungsprefixen viele Möglichkeiten, um Aspekte zu beschreiben. Weitere Informationen können durch Verfeinerung als Unteraspekte ergänzt werden. Wenn innerhalb der Tango-Spezifikation auf andere Aspekte referenziert wird, dann wird die Spezifikation durch die Verwendung von Namen präziser.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Markierung

Siehe auch: Sprachelemente

Markierungen sind Sonderzeichen mit spezieller Bedeutung, die den Aspekten vorangestellt werden. Sie sind nicht Teil des Namens und können deshalb Namen nicht unterscheidbar machen. Markierungen dienen unterschiedlichen Zwecken:

Die Strukturmarkierungen stellen Beziehungen zwischen Aspekten her, dies erzeugt den formalen Rahmen der Tango-Spezifikation. Ein Definitionsblock ist immer der Ausgangspunkt eines Beschreibungsteils, Aufzählung und Liste bezeichnen Unteraspekte in beliebiger Reihenfolge, Sequenz und geordnete Liste machen die Reihenfolge von Unteraspekten signifikant. Bedingung und Verzweigung erlauben die Beschreibung von Wirkungen, die nur in bestimmten Situationen relevant sind.

Meta-Aussagen beschreiben Eigenschaften der Beschreibung selbst. Sie verweisen auf andere Dateien mit Tango-Spezifikationsteilen und sie erlauben, mit Schemas Konventionen zu definieren, die hinter domänenspezifischen Spezialisierungsprefixen stehen.

Durch Zweckmarkierungen werden Aspekte mit grundlegenden Eigenschaften gekennzeichnet. Diese Markierungen sind prinzipiell immer optional, denn der Zweck kann auch im Namen oder der formlosen Beschreibung verdeutlicht werden. Die Bedeutung dieser Markierungen ist in der Tango-Beschreibungssprache festgelegt, und die Verwendung führt zu schärferen Formulierungen, die andernfalls nur durch längliche Erläuterungen in formlosen Beschreibungen oder umfangreichen Schema-Definitionen erreicht werden könnten. Bei der Prüfung und Weiterverarbeitung einer Tango-Spezifikation, und insbesondere bei maschineller Auswertung, sind diese Markierungen wichtige Anhaltspunkte.

Markierungen können vor Namen oder vor allgemeinen formlosen Beschreibungen verwendet werden. Sie können auch kombiniert werden. Dabei ist die Reihenfolge vorgegeben:

  1. Zuerst strukturierende Markierungen, davon Definitionsblock immer zuerst
  2. dann Meta-Markierungen
  3. schließlich Zweck-Markierungen, davon Typ immer zuerst
!#WnEinFenster           // Definitionsblock (Struktur) beschreibt einen Container (Zweck)
    ...

!%Et___                  // Definitionsblock (Struktur) beschreibt ein Schema (Meta)
    ...
 
!_#PrompterFenster       // Definitionsblock (Struktur) beschreibt einen Containertyp (Zweck)
    .{mindestens 10cm breit, mindestens 4 cm hoch}
    .TxPromptertext <- $EXTERN.{PrompterText}
    .+BtJa
        =>  ^JA
    .+{Knopf, um nein zu sagen}  // umständlich für BtNein, formlose Beschreibung mit Markierung
        =>  ^NEIN
    .BtAbbrechen         // ohne Aktivator-Markierung akzeptabel, aber nicht schön
        =>  ^ABBRUCH
 
!!ftp <- "tcpip/ftp.tgo"   // Definitionsblock (Struktur) zieht andere Datei an (Meta)

Fehlerhaft wäre eine Niederschrift der Art

!# WnMeldungenSenden
    .$Meldungen << $EXTERN.{Gesammelte Meldungen}
        .{gesammelte Meldetexte}
    .+Meldungen                      // FEHLER: Name nicht eindeutig
        =>  .USER << $Meldungen

Die Verwendung einer Markierung zur Unterscheidung ist nicht ausreichend, deshalb ist der Name Meldungen im Unteraspektblock nicht eindeutig.

 Stukturmarkierungen werden in bestimmten Situationen weggelassen:

Die Markierung vor einem Pfad kennzeichnet das Ziel des Pfades. Im nachfolgenden Beispiel ist in der Aktion @Blockieren der Aspekt $WnSendeFenster.BtSenden.Aktiv als Zustand markiert, nicht als Container. Der Pfad beginnt zwar bei einem Container, aber er endet bei einem Zustand.

!#WnSendeFenster
    .EtMeldung
    .+BtSenden
        .$Aktiv : [ "Aktiv" | "Inaktiv" ]
    .+BtSendenBlockieren 
        =>  .@Blockieren
    ...

!@Blockieren
    =>  .$WnSendeFenster.BtSenden.Aktiv := "Inaktiv"
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Spezialisierungprefix

Siehe auch: Sprachelemente

Ein Spezialisierungsprefix klassifiziert einen Aspekt aus Sicht der Domäne. Dazu beginnt der Name eines Aspekts mit einer vordefinierten Zeichenkombination. Nur Aspekte mit einem Namen können mit einem Spezialisierungsprefix versehen werden. Spezialisierungsprefixe sind Teil des Namens und deshalb distinktiv. Im folgenden Beispiel werden Fenster mit dem Prefix Wn versehen, Eingabetextfelder mit dem Prefix Et, Bedienknöpfe mit Bt:

!#WnMeldungenSenden 
    .EtMeldungen
        .{Feld für den Meldetext}
    .BtMeldungen        // Aktivatormarkierung fehlt und Name schlecht gewählt
        =>  .USER << "Meldungstext aus EtMeldungen"
    .+BtStop
        =>  .WnMeldungenSenden.CLOSE 
    .{Eingabefeld für irgendeinen Text}

Die Aspekte EtMeldungen und BtMeldungen haben unterschiedliche Spezialisierungsprefixe und damit unterschiedliche Namen. Das formlos beschriebene Feld {Eingabefeld für irgendeinen Text} kann nicht als Eingabetextfeld gekennzeichnet werden, da formlose Beschreibungen nicht mit Spezialisierungsprefixen versehen werden können.

Für jede Domäne kann (und sollte) eine Liste von Spezialisierungsprefixen und deren Bedeutung vereinbart sein. Damit kann auch festgelegt werden, welche terminalen Unteraspekte ein Aspekt enthalten soll. Die Liste der Spezialisierungsprefixe kann als Schema in der Tango-Spezifikation notiert sein. Die nachfolgende Liste enthält die Spezialisierungsprefixe zur Beschreibung von Software, wie sie in diesem Dokument verwendet werden:

Spezialisierungsprefix

Bedeutung

einige terminale Unteraspekte

Wn___

GUI-Fenster

+OPEN, +CLOSE, +OPENMODAL

Tx___

Anzeigetext, nicht editierbar

 

Et___

Text editierbar

+CR, +CHANGED

Bt___

Bedienknopf

 

Ev___

Ereignis-Empfänger

 

Cb___

ComboBox (allgemeiner: Ss___)

$SELECTION

Rb___

Radio-Button (allgemeiner: Ss___)

$SELECTION

Ck___

Check-Button (allgemeiner: Sm___)

$SELECTION, +CHECKED, +UNCHECKED

Lb___

Listbox (allgemeiner: Ss___ oder Sm___)

$SELECTION

Ss___

Selektiere 1 aus n (Select Single)

$SELECTION

Sm___

Selektiere m aus n (Select Multiple)

$SELECTION

Im___

Bild

+CLICK

Ob___

Objekt

+CREATE, +CREATED

Uc___

Use Case

 

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Schema

Die Vereinbarung, was unter einem bestimmten Spezialisierungsprefix verstanden werden soll, kann innerhalb der Tango-Spezifikation niedergeschrieben werden als Schema, markiert mit %. Dies ist nützlich, wenn terminale Unteraspekte erklärungsbedürftig sind, oder wenn festgelegt werden soll, welche Terminale verwendet werden dürfen. So ist z.B. nicht sofort klar, was der Unteraspekt CHANGED bedeuten soll. Dies kann konkretisiert werden:

!%Et___ 
    +CHANGED
        .{wird ausgelöst, wenn der Inhalt geändert ist und das Feld verlassen wird}
    ...

Nach dem Spezialisierungsprefix folgen drei Unterstriche, die den Rest des Namens symbolisieren. Mögliche Erläuterungen zu einem Spezialisierungsprefix können sein:

Die in einem Schema festgelegten Eigenschaften können am einzelnen Aspekt geändert werden. So kann der Aktivator +OPEN eines Wn___-Fensters für jedes Fenster spezielle Aktivitäten anstoßen, mit denen der Inhalt des Fensters korrekt gesetzt wird. Die Änderungen eines Aspekts gegenüber den Definitionen im Schema müssen widerspruchsfrei sein, denn es gibt keine Regel, nach der eine Definition an einem Aspekt die Definition im Schema unwirksam machen würde. Die im Schema getroffenen Aussagen zu +OPEN müssen also unwidersprochen bleiben, wenn die Wirkung des Aktivators irgendwo speziell definiert wird.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Terminaler Aspekt

Siehe auch:Sprachelemente

Aspekte, die in der Domäne hinreichend bekannt sind, müssen nicht mehr weiter erklärt oder verfeinert werden. Ein terminaler Aspekt, kurz Terminal repräsentiert das Ende der Verfeinerung oder Erklärung in einer Tango-Spezifikation. Als terminale Aspekte gelten

Terminale entstehen aus dem Wissen um die Domäne, in der das Produkt erstellt oder eingesetzt wird. Deshalb kann frei entschieden werden, welche Aspekte Terminale sein sollen. Eine Beschreibung kann auch ohne terminale Aspekte überall dort enden, wo die Spezifikation selbst keine weitere Verfeinerung mehr verlangt.

Im Beispiel Anmeldedialog wurden die Aspekte KannArbeiten und Gesperrt nicht mehr weiter verfeinert, weil dies in der Spezifikation nicht relevant ist. Eine explizite Kennzeichnung als Terminal wäre möglich gewesen, ist aber nicht notwendig.

Aspekte können Namen erhalten, die für den kundigen Leser hinreichend aussagekräftig sind, weil sie z.B. der domänenspezifischen Fachsprache entnommen sind. Diese Aspekte müssen nicht mehr weiter verfeinert werden und können als Terminal notiert werden. Ein Softwareentwickler kann sich vorstellen, was hier passiert:

    =>  .WnMeinFenster.CLOSE  
        .*WnAnderesFenster.EtEingabe.FOCUS

FOCUS ist hat eine Markierung als Ereignis, damit klargestellt wird, dass ein Aktivator dieses Namens ausgelöst wird. Die Schreibweise könnte sonst auch auf einen Zustand hindeuten.

Terminale kennzeichnen eine Grenze, jenseits der jeder referenzierte Unteraspekt als vorhanden vorausgesetzt wird, egal ob er tatsächlich definiert wurde oder nicht. Terminale Aspekte erzwingen keine weitere Detaillierung, sie verbieten sie aber auch nicht. Auch die Existenz von Terminalen selbst wird als gegeben hingenommen, deshalb kann im Beispiel Anmeldedialog der terminale Aktivator WnLogin.CLOSE verwendet werden, ohne dass er explizit definiert wurde.

Im folgenden Beispiel werden die Terminale SELECTION, USER, CLOSE und BEEP verwendet ohne irgendwo definiert zu sein. Das Terminal EtIntegerEingabe.CR wird weiter verfeinert, weil spezielle Aktivitäten beschrieben werden müssen. Auch USER.BEEP muss verfeinert werden um den Ausgabeton zu beschreiben.

!WnEingabefenster
    .EtIntegerEingabe
        .+CR         
            =>  ?{Format der neuen Eingabe} =  
                    = "Integer" 
                        =>  .{Passt, akzeptieren}
                            .WnEingabefenster.CLOSE
                    = "NOT Integer"
                        =>  .*USER.BEEP
                                .{besonders nerviger Formatfehler-Ton}
                            .{alten Inhalt in EtIntegerEingabe wieder anzeigen}
                            .EtIntegerEingabe.SELECTION := "Alles selektiert"

Ein Pfad, der in Unteraspekte eines terminalen Aspekts zeigt, wird immer als korrekt akzeptiert, egal ob dieser Unteraspekt explizit niedergeschrieben ist oder nicht. Das Vorhandensein des referenzierten Unteraspekts wird stillschweigend vorausgesetzt. Im obigen Beispiel wird mit dem Ereignis USER.BEEP auf einen Aktivator des Terminals USER zugegriffen. Selbst wenn BEEP kein Terminal wäre, würde die Existenz des dazu gehörenden Aktivators stillschweigend vorausgesetzt, da USER selbst ein Terminal ist.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Ellipse

Siehe auch:Sprachelemente

Eine bewusst unvollständige Beschreibung kann durch eine Ellipse ... markiert werden. Ellipsen stehen immer auf einer eigenen Zeile, außer wenn ein Wirkungspfeil vorausgeht oder ein Kommentar hinter der Ellipse folgt. Die Einrückung der Ellipse sagt aus, welcher Teil der Beschreibung unvollständig ist.

!#WnEinFenster
    .Fensterüberschrift
    .EtEingabefeld1
    .EtEingabefeld2
        ...                   // zu EtEingabefeld2 wäre noch mehr zu sagen
    .+BtAkzeptieren
        =>  ...               // auch die Wirkung von BtAkzeptieren fehlt
    .+BtAbbrechen
    ...                       // es gibt noch weitere Teile von WnEinFenster

...                           // es fehlen noch Definitionsblöcke
    .{Initialisierung nicht vergessen!}
Ein Pfad, der in eine Ellipse hineinzeigt, kann auf jeden beliebigen Unteraspekt referenzieren. Im Beispiel hat EtEingabefeld2 eine Ellipse als Platzhalter für Unteraspekte, BtAbbrechen hat keine. Die Folge ist, dass ein Zugriff auf WnEinFenster.EtEingabefeld2.Sichtbar korrekt ist, ein Zugriff auf WnEinFenster.BtAbbrechen.Sichtbar würde die Spezifikation unvollständig machen.

Eine Ellipse kann durch Unteraspekte verfeinert werden. Hier kann z.B. detailliert werden, welche Aspekte durch die Ellipse ersetzt wurden. Eine Referenz auf diese Unteraspekte ist nicht möglich, weil ein Pfad keine Ellipse als Bestandteil enthalten kann.

Ellipsen sind gedacht für Teile des Produkts, an denen man nicht weiter verfeinern will, weil eine weitere Detaillierung in der Spezifikation ohne Bedeutung ist. Die Referenz auf einen Aspekt, der Teil einer Ellipse ist, unterläuft die Prüfung der Tango-Spezifikation auf Vollständigkeit und sollte vermieden werden.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Mehrfachaspekt  ( , )

Ein Mehrfachaspekt erlaubt die Gruppierung mehrere Aspekte zu einer Einheit, die wie ein einzelner Aspekt verwendet werden kann. Dazu werden mehrere Aspekte durch runde Klammern zusammengefasst und durch Komma voneinander getrennt. Mehrfachaspekte werden hauptsächlich verwendet

Die Syntax von Wertzuweisung, Senden und Inhaltsbeschreibung ermöglicht keine Unteraspekte zur Beschreibung der Werte. Prinzipiell könnte eine solche Beschreibung als Unteraspekt des gesamten Konstrukts hinzugefügt werden, ein Mehrfachaspekt ist in solchen Fällen oftmals besser lesbar.

!$Familie
    ...Mitglied : [ (_Vater, "0..1") | (_Mutter, "0..1") | _Bruder | _Schwester ]
 
!$FamilieNachAlter
    ---Mitglied : [ _Bruder | _Schwester | _Vater | _Mutter ]

!+Init
    =>  .Familie := (Mama, Papa, kleinerBruder, großerBruder, Schwester)
        .FamilieNachAlter := (Papa, Mama, Schwester, großerBruder, kleinerBruder)

!+BtAlleBrüder
    =>  .USER << (kleinerBruder, großerBruder)

Die Inhaltsbeschreibung der Familienmitglieder enthält für Vater und Mutter eine Mengenbegrenzung, die zwei dazu notwendigen Aspekte werden in jeweils einem Mehrfachaspekt zusammengefasst. Die Wertzuweisung an Familie füllt eine Liste mit mehreren Werten aus einem Mehrfachaspekt. In einer Wertzuweisung an eine geordnete Liste könnte die Reihenfolge der Aspekte signifikant sein, wie in FamilieNachAlter. Grundsätzlich sind Mehrfachaspekte ungeordnet, und wenn die Reihenfolge von Bedeutung sein sollte, dann muss dies explizit angegeben werden, üblicherweise als weiterer Aspekt im Mehrfachaspekt. Im Beispiel oben ist nicht klar, ob die nach Alter geordnete Familie tatsächlich der Reihenfolge im Mehrfachaspekt entspricht. Dies kann mit einer allgemeinen formlosen Beschreibung klargestellt werden:

        .FamilieNachAlter := (Papa, Mama, Schwester, großerBruder, kleinerBruder, {in dieser Reihenfolge})

Ein Mehrfachaspekt kann durch eine formlose Wertbeschreibung ersetzt werden. Im nachfolgenden Beispiel wird ein Zahlenintervall beschrieben:

    .EtWürfel1 : (_Integer, "1..6")     // mit Mehrfachaspekt
    
    .EtWürfel2 : "Integer 1..6"         // mit formloser Wertbeschreibung
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Aufzählung  .

Siehe auch: Konzepte

Eine Aufzählung ist eine Menge von ungeordneten Aspekten in einem Unterblock. Jeder Aspekt der Aufzählung wird mit einem führenden Punkt eingeleitet. Eine Aufzählung kann aus Elementen oder Eigenschaften bestehen, oder sie ist Teil eines Aktivitätsblocks und beschreibt Wirkungen, die unter bestimmten Voraussetzungen eintreten. Die Reihenfolge der Aspekte in einer Aufzählung ist ohne Bedeutung, d.h. die Aussage ändert sich nicht, wenn die Aspekte umgestellt werden.

In einem Unterblock, der einen einzigen Aspekt enthält, kann dieser Aspekt mit oder ohne führenden Punkt notiert werden. Die Aussage ändert sich nicht, egal ob der einzelne Aspekt Teil einer Aufzählung ist oder nicht.

Vor dem Wirkungspfeil eines Aktivitätsblocks wird niemals ein Aufzählungspunkt notiert, selbst wenn in diesem Unterblock neben dem Aktivitätsblock weitere Aspekte in einer Aufzählung angeordnet sind. Ebenso werden Bedingungen und Listen immer ohne den Aufzählungspunkt notiert. Fälle, in denen Aufzählungsmarkierungen wahlweise weggelassen werden können, wurden beim Thema Markierung bereits erwähnt. Das nachfolgende Beispiel zeigt gängige Anwendungsfälle von Aufzählungen:

!#WnKnopfsperre
    .+BtPiepsen
        .$Aktiv : [ "Aktiv" | "Inaktiv" ]
        =>  ? BtPiepsen.Aktiv =
                = "Aktiv"
                    =>  {Jetzt kurz piepsen}
                = "Inaktiv"
                    =>  NOP
    .+BtTonAus
        =>  .BtPiepsen.Aktiv := "Inaktiv"
    .+BtTonEin
        =>  .BtPiepsen.Aktiv := "Aktiv"

Wenn der Zweck eines Aspekts markiert ist und die Aussage im Unterblock eindeutig erkennbar ist, dann kann die Aufzählungsmarkierung weggelassen werden. Im Beispiel oben könnten sämtliche Aufzählungsmarkierungen weggelassen werden: 2)

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Sequenz -

Siehe auch: Konzepte

Die Sequenz ist eine geordnete Sammlung von Aspekten in einem Unterblock. Jeder Aspekt der Sequenz wird mit einem führenden Minus - eingeleitet. Diese Sequenzmarkierung wird nur vor einer geordneten Liste weggelassen.

Eine Sequenz wird vorwiegend verwendet

Die Nutzung von Sequenzen außerhalb von Aktivitätsblöcken oder Zuständen ist möglich, aber ungewöhnlich. Eine Sequenz kann gemeinsam mit einer Aufzählung in einem Unterblock stehen, dabei können Aspekte der Aufzählung und Aspekte der Sequenz in beliebiger Reihenfolge niedergeschrieben sein. Alle sequenzmarkierten Aspekte dieses Unterblocks werden als Teil einer einzigen Sequenz betrachtet, und nur für diese Aspekte untereinander ist die Reihenfolge vorgegeben.

Im nachfolgenden Beispiel wird eine Sequenz durch ein einzelnes Element einer Aufzählung unterbrochen. Dies ist ohne Bedeutung, denn die Reihenfolge betrifft die sequenzmarkierten Aspekte untereinander, also erst Strophe1, dann Strophe2. Die Aussage über die Lautstärke bezieht sich auf den gesamten Vorgang in diesem Aktivitätsblock, beide Strophen dürfen nicht lauter sein als Zimmerlautstärke.

!+LiedSingen
    =>  -Strophe1Singen
        .{Obergrenze ist Zimmerlautstärke}
        -Strophe2Singen

Das folgende Beispiel Telefonieren-Protokoll ist die Beschreibung eines Kommunikationsprotokolls. Abläufe dieser Art sind ein typisches Anwendungsfeld für Sequenzen. An diesem Beispiel ist auffällig, dass trotz der sequentiellen Natur von Protokollen die Sequenz als Beschreibungsmittel nur selten verwendet wird. Wenn die nächste Aktivität vom vorher erreichten Ergebnis abhängt, dann ist eine Verzweigung und der Wechsel in einen anderen, geschachtelten Aktivitätsblock die natürliche Art der Beschreibung.


Beispiel einer Tango-Spezifikation: Telefonieren-Protokoll
! Telefon
    .+HörerAbnehmen
    .+HörerAuflegen
    .+NummerWählen

! +IchRufeAn
    .$GewünschteNummer <- $EXTERN.{Rufnummer}
    .$GewünschterGesprächspartner <- $EXTERN.{Gesprächspartner}
    .? @AmtsleitungHolen =   
        = "OK, Amtsleitung da"
            =>  .?Telefon.NummerWählen =
                    = "Rufsignal ohne Reaktion"                        // keiner da
                        =>  .Telefon.HörerAuflegen       
                    = "Besetzt-Signal"
                        =>  .Telefon.HörerAuflegen        
                    = "falscher Gesprächspartner"        
                        =>  .? GESPRÄCHSPARTNER << "Richtiger Anschluss?" = 
                                = "Ja, richtig gewählt"
                                    =>  -{Gespräch führen, evtl. richtigen Gesprächspartner holen lassen}        
                                        -Telefon.HörerAuflegen
                                = "Nein, falscher Anschluss" 
                                    =>  -{entschuldigen}              // wichtig!
                                        -Telefon.HörerAuflegen
                    = "Anrufbeantworter" 
                        =>  .? {Motivation und Worte vorhanden} =
                                = "Ja, ich will mich verewigen"
                                    =>  -{Ansage und Pieps abwarten}
                                        -{Spruch aufsagen}
                                        -Telefon.HörerAuflegen
                                = "Nein, keine Lust"
                                    =>  .Telefon.HörerAuflegen
                    = "richtiger Gesprächspartner"  
                        =>  -{Gespräch führen}                                
                            -Telefon.HörerAuflegen

        = NOK, keine Leitung" 
            =>  .{später nochmals versuchen}
                .Telefon.HörerAuflegen
               
               
!@AmtsleitungHolen   
    =>  .?Telefon.HörerAbnehmen =
            = "Amtsleitung gekriegt"
                =>  .^"OK, Leitung ist da"
            = "Keine Amtsleitung, Telefon tot"
                =>  ?Telefon.{Mehrmals auf die Gabel tippen} =    // bei älteren Telefonen geht das
                        = "Amtsleitung gekriegt"
                            =>  .^"OK, Leitung ist da"
                        = "Immer noch nix" 
                            =>  .^"NOK, Telefon tot"

Sequenzen werden in diesem Beispiel verwendet bei aufeinanderfolgenden Aktivitäten, die keine Ergebniskontrolle benötigen. Diese Situation kommt in diesem Protokoll und in den meisten Abläufen nur dort vor, wo der Detaillierungsgrad der Beschreibung abnimmt.

Die Nutzung von Sequenzen zur Beschreibung von Systemen sollte immer genau hinterfragt werden. Beim ersten Blick auf ein System könnten sich Sequenzen als Beschreibungshilfsmittel anbieten, aber oft zeigt sich bei tieferen Überlegungen, dass die Reihenfolge ein unnötiges Kriterium ist. Sequenzen zwingen die Implementierung, eine bestimmte Reihenfolge einzuhalten, sie setzen damit starke Randbedingungen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Liste  ...

Siehe auch: Konzepte

Eine Liste repräsentiert eine Anzahl ungeordneter gleichartiger Aspekte. Die einzelnen Einträge der Liste haben keine eigenen Namen, auf sie kann nur komplett als Liste oder über einen Filter zugegriffen werden. Der wiederholt auftretende Eintrag wird beschrieben durch einen Namen oder eine formlose Beschreibung, markiert durch drei führende Punkte .... Die Verfeinerung dieses Unteraspekts beschreibt Struktur und Eigenschaften jedes Eintrags in der Liste.

Die Liste ersetzt eine Menge von gleichartigen Aspekten, die andernfalls an derselben Stelle notiert wären. In den folgenden zwei Beispielen wird die separate Notation der Unteraspekte durch eine Liste ersetzt:

!$KundenOhneListe
    .Kunde1
        .Name
    .Kunde2
        .Name
    .Kunde3
        .Name
    .+KundenÜbersichtErstellen

!$KundenListe
    ...Kunde
        .Name
    .§{KundenListe.Kunde hält genau drei Kunden}
    .+KundenÜbersichtErstellen

In der Niederschrift als Liste ist die Anzahl der Kunden variabel, deshalb wird in diesem Beispiel die Anzahl explizit auf drei Kunden festgelegt. Die Einträge der Liste sind nicht benannt, anders als in der Niederschrift ohne Liste, sie können deshalb nur als komplette Liste referenziert werden, oder als Teilmenge, wenn sie durch einen Filter an Hand ihrer Eigenschaften ausgewählt werden.

Eigenschaften jedes Eintrags in der Liste werden als Unteraspekte der Liste notiert. Eigenschaften der Liste selbst stehen gewöhnlich als zusätzlicher Aufzählungspunkt im gleichen Unterblock "neben" der Liste. Wenn Eigenschaften eindeutig der gesamten Liste zuzuordnen sind können sie auch als Unteraspekt der Liste notiert sein, z.B. Angaben über die Größe der Liste. Im Beispiel oben ist die Größe der Liste als Eigenschaft neben der Liste beschrieben, ebenso der Aktivator KundenÜbersichtErstellen, der die ganze Liste benutzt. Der übergeordnete Aspekt ist mit KundenListe benannt, in dem das Wort Liste auftaucht. Dies ist übliche Konvention, wenn dieser Aspekt keine besondere Bezeichnung in der Domäne hat.

In einer Aufzählung können mehrere Listen als Aspekte vorkommen. In diesem Fall wird keine Aussage getroffen über die Reihenfolge, in der die Listen oder ihre Einträge im Unterblock erscheinen, insbesondere könnten die Elemente aller Listen in beliebiger Reihenfolge durchmischt auftreten.

!$AlleAlphaNummerischenZeichen
    ...Großbuchstabe : [ "A..Z" | "Ä" | "Ö" | "Ü" ]
    ...Kleinbuchstabe : [ "a..z" | "ä" | "ö" | "ü" | "ß" ]
    ...Ziffer : "0..9"
    .§{enthält alle Buchstaben und Ziffern}
    .§{jedes Zeichen genau ein Mal}

Großbuchstabe, Kleinbuchstabe und Ziffer treten in AlleAlphaNummerischenZeichen mehrfach auf, allerdings jedes mögliche Zeichen nur genau ein Mal, wie in der letzten Eigenschaft beschrieben. Es gibt keine Aussage über die Reihenfolge der Einträge, weder über die Listen insgesamt (groß vor klein vor Ziffer) noch über die Ordnung innerhalb einer Liste. Die Reihenfolge 2 A ä F 7 b K usw. wäre mit dieser Beschreibung möglich.

Listen können nicht als Teil einer Sequenz auftreten (also -...Element). Listen sind eine Zusammenfassung von Aspekten, die an beliebiger Stelle im Block vorkommen könnten, ohne dass sich die Aussage der Spezifikation ändert. Dies widerspricht dem Wesen einer Sequenz.

Eine Liste hat keinen eigenen Namen, aber ein Pfad, der mit dem Namen oder der Beschreibung des zu wiederholenden Eintrags endet, referenziert keinen speziellen Eintrag, sondern die ganze Liste. Deshalb hält der Zustand $alleKunden im nachfolgenden Beispiel die Liste aller Kunden als Wert:

!+BtSetzeAlleKunden
    =>  .$alleKunden := KundenListe.Kunde     // eine ziemlich sinnfreie Demo
Bei der Nutzung von Filtern muss nicht zwingend die zu filternde Liste referenziert werden. Jeder andere Aspekt, insbesondere auch der zur Liste übergeordnete Aspekt ist ebenso geeignet, solange in der Beschreibung des Filters der Zweck erkennbar ist. Wenn ein Filter mehrere Listen parallel referenziert, dann könnte der übergeordnete Aspekt, der sämtliche Listen enthält, im Filter verwendet werden.

Im folgenden Beispiel wird an USER1 und USER2 dieselbe Information versandt. Für USER1 wird die Liste selbst gefiltert, für USER2 der übergeordnete Aspekt KundenListe, dessen Bestandteil die Liste ist. USER3 bekommt eine ungeordnete Liste aller alphanummerischen Zeichen. Da hierbei drei Listen kombiniert werden müssen, wird der übergeordnete Aspekt AlleAlphaNummerischenZeichen dieser drei Listen im Filter verwendet.

!+BtAlleKunden
    =>  .USER1 << KundenListe.Kunde.{alle Kunden}.Name      // nutzt Namen des wiederholten Eintrags
        .USER2 << KundenListe.{alle Kunden}.Name            // nutzt übergeordneten Aspekt der Liste

!+BtAlleAlphaNummerischenZeichen
    =>  .USER3 << AlleAlphaNummerischenZeichen.{alle Zeichen}  // nutzt übergeordneten Aspekt

Beim Filtern entstehen neue, ungeordnete Listen zusammengesetzt aus dem Inhalt einer oder mehrerer Listen. Der direkte Zugriff auf eine Liste, welche die komplette gesuchte Information enthält, wie für USER4 im nachfolgenden Beispiel, ist kein Filter, sondern ein Pfad, was im Fall einer ungeordneten Liste keinen Unterschied macht. In jedem Aktivitätsblock im folgenden Beispiel wird eine inhaltlich identische Meldung an alle USER versandt, die Filter sind lediglich anders formuliert:

!+BtWähleKunden
    =>  .USER1 << KundeListe.Kunde.{alle Kunden mit Namen ^A.*$}.Name 
        .USER2 << KundeListe.{alle Kunden mit Namen ^A.*$}.Name

!+BtWähleZiffern
    =>  .USER3 << AlleAlphaNummerischenZeichen.{alle Ziffern}
        .USER4 << AlleAlphaNummerischenZeichen.Ziffer       // das ist kein Filter!
        .USER5 << AlleAlphaNummerischenZeichen.Ziffer.{Alle}

!+BtWähleBuchstaben
    =>  .USER6 << AlleAlphaNummerischenZeichen.{alle zwischen "C" und "M"}
        .USER7 << AlleAlphaNummerischenZeichen.Großbuchstabe.{alle zwischen "C" und "M"}

Die Markierung eines Aspekts als Liste ist optional, prinzipiell kann jeder Aspekt eine Liste sein, wenn er so beschrieben ist, z.B. durch eine formlose Beschreibung der Art {Liste aus Kontonummern}.

Die Liste ersetzt viele Aufzählungsmarkierungen und wird deshalb selbst nicht als Teil einer Aufzählung markiert, wie bereits früher erwähnt. Eine Liste kann Einträge halten, die selbst markiert sind, so z.B. Ereignisse, Aktivatoren oder Aktionen. Die Markierung als Liste kann mit anderen Markierungen, üblicherweise Zweckmarkierungen, kombiniert werden, wobei die Listenmarkierung als Strukturmarkierung die führende Markierung ist.

Eine Liste kann um neue Einträge erweitert werden, es können Einträge entfernt oder verändert werden, und die Liste kann auch komplett leer sein. Die Manipulation von Listen ist nicht Teil der Tango-Beschreibungsmethodik, dafür werden üblicherweise terminale Aspekte wie ADD oder ADDALL oder allgemeine formlose Beschreibungen verwendet.

Im folgenden Beispiel Handy-Kundenliste wird eine datenbankähnliche Struktur beschrieben, mit der Kundendaten verwaltet werden. Einzelne Gespräche des Kunden werden zwecks späterer Abrechnung notiert.


Beispiel einer Tango-Spezifikation: Handy-Kundenliste
!$KundeListe
    ...Kunde
        .KundenNr : ( 15stellig, {führende Nullen}, " > 12425 " , {eindeutig in KundeListe} )
        .Name : _String
        .KundeSeit : _Datum 
        .HandyListe
            ...Handy
                .RufNr : ( _Telefonnummer, {eindeutig in KundeListe})  // eigentlich weltweit eindeutig
                .VertragBeginn : _Datum
                .VertragEnde : _Datum
                .NutzungListe
                    ...Nutzung
                        .Von : _DatumUhrzeit
                        .Bis : _DatumUhrzeit
                +EvGespräch
                    =>  .{Gespräch als neuen Eintrag in NutzungListe schreiben}
        .+SendeWerbematerial
            =>  KundeListe.Kunde.{Dieser Kunde} << "Info über die neuesten Tarife"
    .+AlleKundenAbrechnen
    .+SendeWerbematerialAnAlle

Die Eindeutigkeit von KundeListe.Kunde.KundenNr könnte als Eigenschaft von KundeListe betrachtet werden, hier wird sie aber als Eigenschaft von KundenNr beschrieben.

Jedem Kunden könnte Werbematerial zugesendet werden. Um einen bestimmten Kunden, eine Zielgruppe oder alle Kunden zu erreichen wäre möglich:

!+BtSpammer1
    =>  .*KundeListe.Kunde.{Kunde mit KundenNr 18110}.SendeWerbematerial
        .*KundeListe.Kunde.{Kunden mit mindestens einem Gespräch im letzten Monat}.SendeWerbematerial
        .*KundeListe.Kunde.{Alle Kunden}.SendeWerbematerial
        
!+BtSpammer2
    =>  .*KundeListe.{Kunde mit KundenNr 18110}.SendeWerbematerial
        .*KundeListe.{Kunden mit mindestens einem Gespräch im letzten Monat}.SendeWerbematerial
        .*KundeListe.{Alle Kunden}.SendeWerbematerial        

Alle diese Aspekte sind Filter, die den gewünschten Kundenkreis selektieren. Ein Filter erzeugt eine neue ungeordnete Liste mit Referenzen auf die ausgewählten Listeneinträge. Die folgende Formulierung adressiert sämtliche Kunden, ist aber kein Filter, denn es fehlt die Filterbedingung:

!BtRundumschlag
    =>  .*KundeListe.Kunde.SendeWerbematerial 
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Geordnete Liste  ---

Eine geordnete Liste ist eine Liste aus gleichartigen Einträgen in einer bestimmten Reihenfolge. Der mehrfach auftretende Eintrag wird mit drei führenden Minuszeichen --- eingeleitet. Abgesehen von der relevanten Reihenfolge hat eine geordnete Liste alle Eigenschaften einer ungeordneten Liste. Der wiederholt auftretende Eintrag wird als Name oder als formlose Beschreibung notiert, die Verfeinerung dieses Eintrags beschreibt Struktur und Eigenschaften jedes Eintrags.

Die geordnete Liste ersetzt eine Sequenz von einzelnen geordneten Einträgen an gleicher Stelle. Die Ordnung von Einträgen ist besonders relevant bei der Beschreibung von aufeinander folgenden Vorgängen in einem Aktivitätsblock, oder für Datenstrukturen eines Zustands. Beides sind implementierungsnahe Beschreibungen, die starke Randbedingungen für die nachfolgenden Stufen einer Produktentwicklung oder für einen Test vorgeben. Deshalb sollte die Verwendung einer geordneten Liste als Beschreibungsmittel vorab genau bedacht werden.

Die geordnete Liste wird als Ganzes verwendet, oder es werden durch einen Filter ein oder mehrere Einträge ausgewählt. Ein Filter auf eine geordnete Liste kann sich auf die Eigenschaften oder auf die Reihenfolge der Einträge beziehen, z.B. {erster Eintrag} oder {die nächsten fünf Einträge}. Ein Filter erzeugt eine ungeordnete Liste aus Referenzen auf die Einträge in der geordneten Liste. Soll durch Filterung wieder eine geordnete Liste entstehen, so muss dies in der Beschreibung des Filters oder durch einen eigenen Aspekt festgelegt werden.

Eine geordnete Liste ist "grundlos" geordnet, ein Ordnungskriterium kann, muss aber nicht angegeben werden. Das Manipulieren geordneter Listen wie Einfügen und Löschen von Einträgen oder Neuordnung ist domänenspezifisch und wird deshalb üblicherweise mit terminalen Aspekten beschrieben. In diesen Aspekten wird erklärt, wie die Ordnung erstellt oder beibehalten werden kann, z.B. {als letzten Eintrag einfügen}.

Im nachfolgenden Beispiel ergibt sich die Ordnung der Einträge aus dem vorhandenen Text. Im Namen der manipulierenden Aktivatoren wird erklärt, wie die Ordnung beibehalten wird:

!$Text
    ---Zeile
        ---Wort    // Annahme: keine getrennten Wörter
            +WortDavorEinfügen
        +WortAnhängen
        +ZeileDavorEinfügen
    +ZeileAnhängen
    +TextSpeichern

Die Aktivatoren in diesem Beispiel sind den Aspekten so zugeordnet, dass möglichst wenig Information an den hier nicht spezifizierten Aktivitätsblock durchgereicht werden muss. Der Aktivator WortDavorEinfügen ist Unteraspekt eines Wortes, und wenn dieses Wort durch einen Filter identifiziert wurde, dann muss nur mehr das neue Wort angeliefert werden, die Einfügeposition ist zu diesem Zeitpunkt bereits bekannt.

In einem Block können mehrere geordnete Listen auftreten. Dadurch wird die Reihenfolge aller sequenzmarkierten Aspekte und der Einträge der geordneten Listen festgelegt, es entsteht eine einzige große Sequenz aller dieser Aspekte. Geordnete Listen als Aspekte einer Aufzählung (also .---Eintrag) machen keinen Sinn, da die Aufzählung selbst ungeordnet ist. Eine geordnete Liste in einem Block muss Teil einer Sequenz sein, deshalb kann das führende Minus, das die Sequenz explizit bezeichnen würde, entfallen, wie bereits im Kapitel Markierungen erwähnt.

!$AlleAlphaNummerischenZeichenTeilsortiert
    ---Ziffer : ("0..9", {sortiert nach aufsteigendem Zahlenwert})
    ---Großbuchstabe : [ "A..Z" | "Ä" | "Ö" | "Ü" ]
    ---Kleinbuchstabe : [ "a..z" | "ä" | "ö" | "ü" | "ß" ]
        .{sortiert nach aufsteigendem ASCII-Wert}
    .§{enthält alle Buchstaben und Ziffern}
    .§{jedes Zeichen genau ein Mal}

In AlleAlphaNummerischenZeichenTeilsortiert folgen auf alle Ziffern alle Großbuchstaben, danach alle Kleinbuchstaben. Diese Gruppen sind selbst geordnete Listen, aber nur für Ziffern und Kleinbuchstaben wird das Ordnungskriterium angegeben. Es ist nicht festgelegt, wie die geordnete Liste Großbuchstabe geordnet ist.

Ein Pfad auf eine geordnete Liste referenziert die gesamte Liste, dabei wird die Ordnung beibehalten. Dagegen erzeugt ein Filter eine neue, ungeordnete Liste mit Referenzen auf die gefilterten Einträge, oder eine neu geordnete Liste, wenn die neue Ordnung explizit notiert ist. Die neue Ordnung kann sich auf die alte Ordnung beziehen.

!+BtTextVorlesen1
    =>  .*USER1.lautVorlesen << Text.Zeile.Wort
        .*USER2.lautVorlesen << Text.Zeile
        .*USER3.lautVorlesen << Text
  
!+BtTextVerjandeln
    =>  .*USER4.lautVorlesen << Text.{Alle Zeilen}.{Alle Worte}
        .*USER5.lautVorlesen << Text.{Alle Zeilen}.Wort

!+BtTextVorlesen2
    =>  .*USER6.lautVorlesen << Text.{Alle Zeilen wie gehabt}.{Alle Worte wie gehabt}

USER1, USER2 und USER3 erhalten Text in der richtigen Struktur. Auf die geschachtelten geordneten Listen wird mit einem Pfad zugegriffen, damit bleibt die Ordnung der geordneten Listen erhalten. USER4 erhält Wortsalat, denn zwei Filterbedingungen zerstören die Ordnung des Textes. USER5 erhält ebenfalls zerstörten Text. Obwohl nur die Zeilen gefiltert werden ist das Gesamtergebnis ungeordnet, es sind also nicht nur die Zeilen durcheinander geraten, sondern auch die Worte. USER6 erhält lesbaren Text, denn in den Filterbedingungen wird die Ordnung des Ergebnisses festgelegt.

Eine geordnete Liste stellt eine starke Implementierungsrestriktion dar, deshalb sollte die Verwendung genau durchdacht werden. In vielen Fällen ist die ungeordnete Liste ausreichend. Der Unterschied zwischen Sortierung und Ordnung kann bei der Entscheidung helfen:

Sortierung
Anordnung von Listeneinträgen nach Kriterien, die von den Einträgen selbst abgeleitet werden können, z.B. Sortierung alphabetisch oder nach Größe.
Ordnung
Anordnung von Listeneinträgen nach Kriterien, die nicht aus den Einträgen abgeleitet werden können, z.B Eingangszeitpunkt oder Reihenfolge von Operationen. Die Ordnung ist eine zusätzliche Information.

Die Ordnungsreihenfolge ist eine Information, die eine geordnete Liste zusätzlich zu den Einträgen verwaltet. Eine Sortierung muss nicht explizit verwaltet werden, denn zum Zeitpunkt, an dem die Sortierung relevant wird, kann die Reihenfolge generiert werden. Für eine Sortierung genügt deshalb meist eine ungeordnete Liste mit entsprechenden Sortierhinweisen an den lesenden Operationen. Dies schafft die maximale Freiheit für eine spätere Implementierung. Eine Ordnung kann in eine Sortierung umgewandelt werden, indem das ordnende Kriterium als zusätzlicher Aspekt jedes Listeneintrags definiert wird, wie im folgenden Beispiel einer First In First Out-Warteschlange demonstriert:


Beispiel einer Tango-Spezifikation: Warteschlange
!$Warteschlange
    ...Auftrag
        .Ankunftszeit : _Uhrzeit 
        ...  
    .$ältesterAuftrag <- Warteschlange.Auftrag.{früheste vorhandene Ankunftszeit}
    .+NächstenAuftragBearbeiten                             // FIFO-Prinzip
        =>  .$ältesterAuftrag.BEARBEITEN
            .$ältesterAuftrag.ENTFERNEN
    .+NeuenAuftragEintragen
        =>  .$Warteschlange.HINZUFÜGEN << ( EXTERN.{NeuerAuftrag}, {Ankunftszeit})

Hier wird das ordnende Kriterium Ankunftszeit als Unteraspekt zu jedem Auftrag beschrieben, damit erübrigt sich die Verwendung einer geordneten Liste. Dieser Weg wäre nicht geeignet, wenn das ordnende Kriterium erkennbar gekünstelt wäre wie im Falle der KommandoListe im Beispiel Kommandofenster:

                   = "Mehrere Kommandos" 
                       => .KommandoListe <- Selektion 
                              ---Kommando

Die Selektion wird als KommandoListe interpretiert, die aus geordneten Kommandos besteht. Die Ordnung ergibt sich aus der Reihenfolge, in der die Kommandos niedergeschrieben sind, hier ist die geordnete Liste das natürliche Beschreibungsmittel.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Pfad

Siehe auch: Sprachelemente

Ein Aspekt kann an verschiedenen Stellen der Spezifikation von Bedeutung sein. Durch die Angabe eines absoluten Pfades können einzelne Aspekte oder ganze Listen referenziert werden. Dazu wird, beginnend beim Kopfaspekt eines Definitionsblocks in der aktuellen Datei, der Weg über die Teile-Beziehung hin zum gewünschten Aspekt notiert, jeder Schritt getrennt durch einen Punkt vom nächsten Schritt. Die einzelnen Schritte werden auch dann mit einem Punkt getrennt, wenn der Pfad in eine Sequenz oder eine geordnete Liste hinein referenziert.

Im Beispiel Anmeldedialog zeigt der Pfad WnLogin.EtPasswort.Inhalt im Aktivitätsblock zu +InitLogin auf den Aspekt, der den Inhalt des Passwort-Feldes beschreibt. Der Pfad WnLogin.EtPasswort.SELECT verweist aus der Aktion @JetztAnmelden auf einen terminalen Aktivator, der nicht explizit als Unteraspekt von WnLogin.EtPasswort aufgeführt ist, aber bei Eingabetextfeldern vorausgesetzt wird. Mit dem Pfad WnLogin.EtPasswort.TxAnzeige.LEER könnte ein möglicher Zustand des Anzeigetextes referenziert werden, denn die Werte des Zustands sind Unteraspekte des Zustands selbst.

Ein relativer Pfad beginnt mit einem im gegebenen Kontext eindeutigen Aspekt, der nicht der Kopfaspekt eines Definitionsblocks ist. Relative Pfade können nur verwendet werden, wenn die referenzierende Stelle und der referenzierte Aspekt innerhalb desselben Kontextes liegen. Im kürzesten Fall besteht ein relativer Pfad aus dem Namen des gewünschten Aspekts allein.

Relative Pfade werden restriktiv interpretiert, jede mögliche Missinterpretation macht die Spezifikation fehlerhaft. Es gibt keine Mechanismen, um Mehrdeutigkeiten aufzulösen oder Lücken zu komplettieren. Insbesondere gibt es auch keine Regel, dass lokal bekannte Namen weiter entfernt definierte Namen ausblenden würden, wie dies in Programmiersprachen bei lokalen und globalen Variablen üblich ist.

Im nachfolgenden Beispiel Kundenkontakt-Verwaltung ist das Bearbeitungsfenster in Bereiche geteilt, so dass die Kundendaten optisch und logisch strukturiert sind. Daraus ergibt sich eine tiefe Verschachtelung der Felder in Unteraspektblöcke und Aktivitätsblöcke. Der Kontext, den der Definitionsblock für WnKundenkontaktVerwaltung bildet, umfasst das ganze Beispiel, deshalb können überall relative Pfade verwendet werden.


Beispiel einer Tango-Spezifikation: Kundenkontakt-Verwaltung
!#WnKundenkontaktVerwaltung
    .#WnKunde
        .EtKundenNr
        .EtName
        .EtKundeSeit : _Datum 
        .#WnTelefon
            .EtTelNr
            .EtLetzterKontakt : _DatumUhrzeit
            +BtTelefonAnrufen
                =>  .?{Verbindung über Telefon wird hergestellt} =
                        = {hat geklappt}
                            =>  WnTelefon.EtLetzterKontakt := {Zeitpunkt dieses Anrufs}
                        = {keiner oder der Falsche dran}
                            =>  NOP
        .#WnHandy
            .EtHandyNr
            .EtLetzterKontakt : _DatumUhrzeit
            .+BtHandyAnrufen
                =>  .?{Verbindung über Handy wird hergestellt} =
                        = {hat geklappt}
                            =>  WnHandy.EtLetzterKontakt := {Zeitpunkt dieses Anrufs}
                        = {keiner oder der Falsche dran}
                            =>  NOP
        .+BtKundeSpeichern
            =>  .{Kunde in der Datenbank speichern oder aktualisieren}
        .+BtAnPartnerTelefonmarketingWeitergeben
            =>  .CALLCENTER << (EtName, EtTelNr, EtHandyNr)
    .+BtKundeWählen
        =>  .?{im extra Fenster neuen Kunden auswählen} =
                = {Neuer Kunde gewählt}
                    =>  {in WnKunde einfüllen}
                = {Kein neuer Kunde gewählt}
                    =>  NOP
    .+BtSchließen
        ...
Die Übergabe der Kundeninformation an das CALLCENTER wird mit relativen Pfaden beschrieben. Die verwendeten Namen EtName, EtTelNr und EtHandyNr sind im Kontext eindeutig und werden ohne weitere Pfadangaben verwendet, obwohl sie in Blöcken unterschiedlicher Schachtelungstiefe definiert sind. Der Name EtLetzterKontakt ist im Kontext nicht eindeutig und ist als relativer Pfad nicht zulässig, deshalb wird im Aktivitätsblock zu BtTelefonAnrufen der entsprechende Aspekt mit einem Pfad beschrieben, der beim eindeutigen Namen WnTelefon beginnt.

Es kann kein Pfad erzeugt werden, der einen ganzen Aktivitätsblock referenziert oder der in einen Aktivitätsblock hineinzeigt. Ein Aktivitätsblock ist nur unter bestimmten Bedingungen relevant, und diese Bedingungen können nicht erfüllt sein, wenn von einer anderen Stelle der Spezifikation aus referenziert werden soll. Wird ein Aktivitätsblock in einer Aktion niedergeschrieben, so kann zwar nicht der Aktivitätsblock selbst, aber die Aktion referenziert werden.

Die Referenz auf Eigenschaften ist möglich, macht aber gewöhnlich wenig Sinn, da Eigenschaften umfassende Gültigkeit haben und ein Zitieren lediglich das Wiederholen von ohnehin bereits gültigen Aussagen bedeutet.

Die Referenz auf einen Aspekt in einer anderen Datei der Spezifikation beginnt mit dem Kopfaspekt des Include-Definitionsblocks dieser Datei. Der nächste Schritt führt über den Kopfaspekt eines Definitionsblocks in der anderen Datei.

Wenn das Beispiel Anmeldedialog Teil einer Spezifikation aus mehreren Dateien wäre und selbst in anmdatei.txt stünde, dann kann von einer anderen Datei aus auf Aspekte des Anmeldedialogs zugegriffen werden:

!! anm <- "anmdatei.txt"

!#WnZeigeUsername
    .TxUsername : [LEER | _String ]
    .+BtAktualisieren
        =>  -*anm.InitLogin
            -TxUsername := anm.WnLogin.EtUserName

Ein absoluter oder relativer Pfad zeigt immer auf genau einen Aspekt in der Spezifikation. Dieser Aspekt kann den wiederholten Eintrag in einer Liste oder einer geordneten Liste beschreiben, in diesem Fall wird die gesamte Liste referenziert. Der Pfad kann auch zu einem Unteraspekt eines Eintrags in der Liste führen, so dass ein bestimmter Unteraspekt jedes Eintrags in dieser Liste referenziert wird. Im folgenden Beispiel wird mit BtAlleStudenten eine ungeordnete Liste der Namen aller Studenten an USER versandt.

!$StudentListe
    ...Student
        .Name
        .Matrikelnummer

!+BtAlleStudenten
    =>  USER << StudentListe.Student.Name

Jeder Schritt in einem Pfad ist eindeutig. Dies wird im Allgemeinen durch die Verwendung von Namen sicher gestellt, die in der Spezifikation bekannt sind und die auf einzelne Aspekte referenzieren. Als eindeutig gilt auch, wenn schlussendlich mehrere Einträge einer Liste ausgewählt sind, entscheidend ist hier die Eindeutigkeit jedes Schrittes im Pfad, nicht das Ergebnis. Wenn formlose Beschreibungen oder nicht eindeutige Konstrukte wie z.B Auswahllisten als Schritt verwendet werden, dann wird dieser Pfad zu einem Filter.

Das nachfolgende Beispiel Taschenrechner zeigt die Nutzung absoluter und relativer Pfade an einem etwas größeren Fall. Hier wird kein realer Taschenrechner beschrieben, sondern das virtuelle Pendant, deshalb kann in den Eingabetextfeldern etwas anderes als eine Zahl stehen. Die Reihenfolge, in der die Felder ausgefüllt werden, ist frei, zusätzlich lässt sich die Berechnungsfunktion an vielen Stellen auslösen. Dadurch entstehen viele Situationen, auf die unterschiedlich reagiert werden muss.


Beispiel einer Tango-Spezifikation: Taschenrechner
!+Init
    =>  .WnKalkulator.EtWert1 := ""
        .WnKalkulator.EtWert2 := ""
        .WnKalkulator.TxErgebnis := ""
        .SsOperation := "Plus"

!#WnKalkulator
    .EtWert1 : [ "Leer" | "Zahl" | "Keine Zahl" ]
        .+MODIFY                        // jede kleinste Änderung löscht das alte Ergebnis
            =>  .TxErgebnis := ""
        .+CR
            =>  .?EtWert2 =
                    = "Leer"
                        =>  .{in Feld EtWert2 gehen}
                    = [ "Zahl" | "Keine Zahl" ]
                        =>  @JetztBerechnen
    .EtWert2 : [ "Leer" | "Zahl" | "Keine Zahl" ]
        .+MODIFY
            =>  .WnKalkulator.TxErgebnis := ""
        .+CR
            =>  .?WnKalkulator.EtWert1 =
                    = "Leer"
                        =>  .{in Feld WnKalkulator.EtWert1 gehen}
                    = [ "Zahl" | "Keine Zahl" ]
                        =>  @JetztBerechnen
    .SsOperation : [Plus | Minus | Mal | Dividiert]   // Select single, Auswahl aus einer Liste 
        .+MODIFY
            =>  .TxErgebnis := ""
    .TxErgebnis : [ "" | "Zahl" | "Error" ]
    .+BtBerechnen
        =>  @JetztBerechnen
    .+BtEnde
        =>  .WnKalkulator.CLOSE

!@JetztBerechnen
    =>  .#Wk <- WnKalkulator
        .?Wk.EtWert1 =
            = "Leer"
                =>  .{in Feld Wk.EtWert1 gehen}
                    .Wk.TxErgebnis := ""
                    .BEEP
            = "Zahl"
                =>  .?Wk.EtWert2 =
                        = "Leer"
                            =>  .{in Feld Wk.EtWert2 gehen}
                                .Wk.TxErgebnis := ""
                                .BEEP
                        = "Zahl"
                            =>  .Wk.TxErgebnis := "Wk.SsOperation (Wk.EtWert1, Wk.EtWert2)"
                        = "Keine Zahl"
                            =>  .{in Feld Wk.EtWert2 gehen}
                                    .{ganzer Inhalt selektiert}  // hier als Unteraspekt formuliert, s.u.
                                .Wk.TxErgebnis := ""
                                .BEEP
            = "Keine Zahl"
                =>  .{in Feld Wk.EtWert1 gehen}
                    .{Inhalt von Wk.EtWert1 selektiert}       // hier als eigener Aspekt formuliert, s.o.
                    .Wk.TxErgebnis := ""
                    .BEEP
Im Fenster #WnKalkulator können Berechnungen durchgeführt werden. Der eigentliche Berechnungsvorgang wird in der Aktion @JetztBerechnen beschrieben. Diese Anwendung akzeptiert falsche Eingaben in den Feldern solange, bis tatsächlich berechnet werden soll. Die Aktivatoren, die zu einzelnen Feldern gehören, führen zu unterschiedlichen Wirkungen, abhängig vom Inhalt des jeweils anderen Eingabefeldes.

Im Aktivitätsblock zu +Init wird auf die Aspekte in WnKalkulator mit absoluten Pfaden zugegriffen, mit Ausnahme des relativen Pfades SsOperation. Diese Referenz funktioniert, weil SsOperation im Kontext dieser Datei und auch der ganzen Spezifikation eindeutig ist. Dieser relative Pfad auf einen eindeutigen Namen in einem anderen Definitionsblock ist zwar korrekt, aber im Allgemeinen unschön.

In den Aktivitätsblöcken der Aktivatoren von WnKalkulator.EtWert1 wurden relative Pfade verwendet, um auf die anderen Felder zuzugreifen, bei den Aktivatoren von WnKalkulator.EtWert2 sind die absoluten Pfade angegeben. EtWert1, EtWert2 und TxErgebnis sind im Kontext eindeutig, deshalb ist der absolute Pfad eigentlich immer unnötig.

Zur Schreibvereinfachung wird in der Aktion @JetztBerechnen ein Verweis #Wk auf das Fenster #WnKalkulator definiert, der nur innerhalb dieses Aktivitätsblocks und seinen geschachtelten Aktivitätsblöcken verwendet werden kann. Alle Felder des Fensters werden damit über absolute Pfade referenziert, was die bevorzugte Vorgehensweise ist, wenn aus einem Definitionsblock auf Aspekte eines anderen Definitionsblocks zugegriffen wird.

WnKalkulator.BtEnde beschreibt das Schließen des Fensters. Ein einfaches CLOSE als relativer Pfad in diesem Aktivitätsblock ist nicht ausreichend. Es muss erkennbar sein, zu welchem Element dieser terminale Unteraspekt gehört, der im Fenster WnKalkulator selbst nicht beschrieben ist. BEEP gehört zu keinem Element, ist also ein Terminal, dessen Definitionsblock hier nicht angegeben ist.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Filter

Ein Filter ist ein Pfad, in dem mindestens ein Schritt durch ein nicht eindeutiges Selektionskriterium beschrieben ist. Dieses Kriterium kann sich auf Eigenschaften von Aspekten beziehen, oder es können explizit mehrere Aspekte in diesem Schritt angegeben werden. Ein wiederholbarer Eintrag in einer Liste ist eindeutig, deshalb entsteht dadurch allein noch kein Filter, sondern nur ein gewöhnlicher Pfad.

Ein Filter selektiert einen oder mehrere Aspekte, diese müssen nicht notwendigerweise Unteraspekte eines gemeinsamen Aspekts sein, der Filter kann prinzipiell jede Art von Aspekten in der Ergebnisliste kombinieren. Insbesondere können auch mehrere Listen zu einer Einzigen zusammengefasst werden. Durch Filtern entsteht eine neue, ungeordnete Liste mit den Referenzen auf die zutreffenden Aspekte Wenn explizit eine Ordnung der neuen Liste im Filter angegeben ist, dann ist das Ergebnis eine geordnete Liste.

Ein nicht eindeutiges Selektionskriterium könnte sein:

Für die Unterscheidung zwischen Pfad und Filter ist die Art der Beschreibung relevant. So ist ein Pfad mit einer formlosen Beschreibung oder einer Auswahlliste immer ein Filter, selbst wenn das Selektionskriterium objektiv eindeutig wäre, wie z.B. {gesamte Liste}, {der Unteraspekt EtNeuerText} oder [ Maier ].

!#WnMeinFenster
    .TxHallo : "Hallo" 
    .EtEingabe
    .+BtRotFärben
        =>  .WnMeinFenster.{alle Nicht-Knöpfe}.SCHRIFTFARBE := ROT
  
!$Lexikon
    ...Eintrag
        .Wort
        .Artikel : [ "der" | "die" | "das" | "" ]
        .Beschreibung 
        
!+BtSucheImLexikon  
    =>  .USER << Lexikon.Eintrag.{Wortanfang "M" und Artikel "der"}

Der Filter auf WnMeinFenster nutzt den übergeordneten Aspekt aller gefilterten Elemente, also das Fenster selbst im Pfad. Für den Filter auf das Lexikon wird die Liste im Pfad referenziert mit Lexikon.Eintrag, der übergeordnete Aspekt Lexikon wäre ebenso brauchbar. Entscheidend für einen Filter ist nicht, welche Aspekte im Pfad verwendet werden, sondern die klare Beschreibung des Zwecks. Dies ist nützlich, wenn ein Filter Aspekte aus verschiedenen Teilen der Spezifikation zusammensucht und daraus eine einzige Liste generiert. Im folgenden Beispiel wäre die Wahl eines passenden übergeordneten Aspekts schwierig, deshalb werden nur die Filterbedingungen selbst angegeben:

!+BtGesamteBeschriftungBlau
    =>  .*{Alle Fenster im Produkt}.{Alle Beschriftungen}.BlauFärben

In der Trefferliste kann auf Unteraspekte jedes Treffers zugegriffen werden, wie z.B. auf das Terminal SCHRIFTFARBE, das in allen gewählten Unteraspekten von WnMeinFenster vorhanden ist, oder auf den Aktivator BlauFärben, der für alle Beschriftungen im Beispiel existieren muss.

Durch Filterung entsteht immer eine ungeordnete Liste, auch wenn die ursprüngliche Liste geordnet war. Soll das Ergebnis geordnet sein, dann kann dies durch expliziten Hinweis auf die neue Ordnung geändert werden. Es folgen einige Möglichkeiten, dies niederzuschreiben:

!$EinText
    ---Zeile                // eine geordnete Liste, die Zeilenreihenfolge ist relevant 

!+SammleGeordneteZeilen
    =>  .$AlleAZeilen1 := EinText.Zeile.{Alle Zeilen mit ^A.*$}
            .{geordnet wie EinText}
        .$AlleAZeilen2 := EinText.Zeile.{Alle Zeilen wie (^A.*$), geordnet wie EinText} 
        .$AlleAZeilen3 := EinText.Zeile.{Alle Zeilen wie (^A.*$), geordnet wie EinText}
            ---Zeile
        .$AlleAZeilen4 := EinText.Zeile.{Alle Zeilen wie (^A.*$)}.{geordnet wie EinText}

Jede dieser Möglichkeiten ist geeignet, die Ordnung der neuen Liste zu beschreiben. $AlleAZeilen1 wird mit einer Eigenschaft verfeinert, $AlleAZeilen2 und $AlleAZeilen3 enthalten die Ordnungsinformation im Filter selbst. $AlleZeilen3 wird in der Verfeinerung als geordnete Liste beschrieben, wobei dies allein nicht reichen würde, da ohne die Ordnung im Filter nicht klar wäre, wonach geordnet wird. Für $AlleAZeilen4 wird die Ordnung durch einen terminalen Aspekt auf die durch Filterung entstandene Liste beschrieben.3)

In der Notation unterscheiden sich Filter oftmals nicht von formlosen Unteraspekten. So kann nicht unterschieden werden, ob WnMeinFenster.{alle Nicht-Knöpfe} ein Filter oder ein terminaler Unteraspekt ist. Diese Unterscheidung ist unnötig, denn aus Sicht der Tango-Beschreibungsmethodik hat das Fenster WnMeinFenster den zusätzlichen Aspekt und damit die Fähigkeit, den gewünschten Teil seiner Aspekte als Liste liefern zu können.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Verweis <-

Ein Verweis erlaubt auf einen Aspekt mit einem neu gewählten Namen Bezug zu nehmen. Der Aspekt kann in der Spezifikation bereits vorhanden sein, oder er wird bei der Definition des Verweises erstmals beschrieben, z.B. durch eine formlose Beschreibung. Ein Verweis verknüpft einen neuen, benannten Aspekt mit einem anderen, diese Verknüpfung ist unveränderlich.

Der bezogene Aspekt kann sowohl mit dem neu vergebenen Namen als auch über den ursprünglichen Pfad, soweit vorhanden, referenziert werden. Beide Möglichkeiten zum Zugriff sind völlig gleichwertig, der Zustand des Aspekts kann wahlfrei gelesen und verändert werden. Es gibt de Facto nur einen einzigen Aspekt, der jetzt auf verschiedenen Wegen angesprochen wird.

Ein Verweis kann als Schreibvereinfachung genutzt werden. Dies ist nützlich, um lange oder oft wiederholte Pfade kürzer zu notieren4). Daneben kann mit einem Verweis das automatische Synchronisieren von Zuständen beschrieben werden. Das folgende Beispiel Index-Detail-Fenster zeigt an Hand zweier synchronisierter Fenster typische Anwendungsfälle für Verweise.


Beispiel einer Tango-Spezifikation: Index-Detail-Fenster
!#WnOverview
    .$LbItemList
        ...Item
            +BtTitle
                .TxTitle
            .$MoreInfo
        .thisItem <- ({entry currently selected}, [ "" | _LbItemList.Item ])
            .+CHANGED
                =>  .Wd <- WnDetail
                    .? thisItem =
                        = ""
                            =>  Wd.TxExplain := "Please select an item"
                        = _LbItemList.Item
                            =>  Wd.TxExplain := thisItem.MoreInfo
 
!#WnDetail
    .TxExplain
    .AnItem <- WnOverview.LbItemList.thisItem
    .+BtClearItem
        =>  .AnItem := ""
            .TxExplain := "Please select an item"

Die Listbox WnOverview.LbItemList hält die Liste aller auswählbaren Einträge in +BtTitle, sowie zusätzliche Information in $MoreInfo, die in WnDetail angezeigt wird, sobald der Eintrag im Fenster WnOverview ausgewählt wird. Mit dem Knopf WnDetail.BtClearItem kann die Selektion in der Listbox entfernt werden.5)

thisItem wird definiert als Verweis auf den aktuell gewählten Eintrag in der Listbox. Jede Änderung der Auswahl ändert auch thisItem. Die aktuelle Selektion erhält damit einen Namen und muss nicht bei Bedarf jedesmal erneut formlos beschrieben werden. Dieser Aspekt ist in WnDetail unter dem Namen AnItem ebenfalls verfügbar.

Im Aktivitätsblock zu WnOverview.thisItem.CHANGED ist der Verweis Wd als Schreibvereinfachung definiert, er bringt keine neue Information in die Spezifikation, nur neue Möglichkeiten zum Referenzieren eines vorhandenernAspekts.

CHANGED wird ausgelöst, wenn in der Listbox ein anderer Eintrag ausgewählt wird. Dieser Zusammenhang ist im Beispiel nicht explizit beschrieben, weil dies zum Spezialisierungsprefix Lb___ gehörendes bekanntes Domänenwissen ist.6)

Die Verwendung von Verweisen hat eine inhaltliche und eine organisatorische Seite. Wird ein Name für den Zugriff auf einen bereits bekannten Aspekt oder auf eine formlose Beschreibung definiert, so ist dies eine Vereinbarung, die mit dem eigentlichen Inhalt der Spezifikation nichts zu tun hat, denn auch ohne diese Definition könnte auf diesen Aspekt zugegriffen werden. Wenn dagegen der neu entstehende Aspekt über die Schreibvereinfachung hinaus eine Bedeutung als Unteraspekt hat, so wird mit dem Verweis eine Abhängigkeit von einem Zustand des Produkts beschrieben. Der Verweis zu WnDetail.AnItem ist ein Hinweis, dass WnDetail von einem Zustand von WnOverview abhängt.

In einem Aktivitätsblock kann die Definition eines Verweises nichts anderes als eine Schreibvereinfachung sein, da Aspekte in Aktivitätsblöcken nicht von außerhalb referenziert werden können, vom Verweis kann also niemand außerhalb des Aktivitätsblocks Kenntnis nehmen.

Die Definition von Verweisen in Sequenzen und geordneten Listen ist problematisch, denn dies widerspricht dem dauerhaften Charakter von Verweisen. Ein Verweis beschreibt eine Eigenschaft, die immer gültig ist, unabhängig davon, wo in der Spezifikation der Verweis niedergeschrieben ist. Mit dem iterativen Charakter von Sequenzen und geordneten Listen ist dies nicht vereinbar. Wird ein Verweis in einer Sequenz benötigt, so wird dieser Verweis sinnvollerweise in einer Aufzählung neben der Sequenz definiert. Dies ist ein typischer Fall, weshalb Sequenzen und Aufzählungen in einem Unterblock gemischt werden.

Ein Verweis, der auf einen Eintrag in einer Liste, einer Sequenz oder einer geordneten Liste zeigt, kann zur Beschreibung von Iteratoren genutzt werden, wenn eine derartige implementierungsnahe Beschreibung notwendig ist.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Interpretation <-

Die Interpretation ist ein Verweis, der durch Unteraspekte verfeinert wird. Damit kann ein Aspekt auf eine andere Weise interpretiert werden als in der ursprünglichen Definition vorgesehen. Bei der Nutzung des Verweisnamens kann sowohl die Interpretation als auch die ursprüngliche Struktur des referenzierten Aspekts verwendet werden, bei Nutzung des originalen Pfades ist nur die ursprünglich definierte Struktur sichtbar. Zustandsänderungen unter Verwendung der Interpretation ändern den Zustand des referenzierten Aspekts wie bei jedem anderen Verweis.

Die Interpretation wird verwendet, wenn strukturierte Information auf eine andere Weise gelesen werden muss. Im nachfolgenden Beispiel Kommandofenster können in einem Editorfenster ein oder mehrere Kommandozeilen selektiert werden, die dann als Kommando ausgeführt werden. Je nach Inhalt muss der selektierte Text anders interpretiert und bearbeitet werden.


Beispiel einer Tango-Spezifikation: Kommandofenster
!#WnEditorFenster
    .EtText
    .Selektion : [ NULL | _String ]
    .+BtExecute   
        =>  .?Selektion =
                = NULL
                    =>  .BEEP
                = [ "Syntaxfehler" | "kein Kommando" ]
                    =>  .USER << "Syntaxfehler"
                        .{keine Kommandos ausgeführt}
                = "Einzelnes Kommando"
                    =>  .@KommandoAusführen << Selektion
                = "Mehrere Kommandos"
                    =>  .KommandoListe <- Selektion
                            ---Kommando
                        .?KommandoListe.Kommando.{Alle} =
                            = "Mindestens eines kann nicht ausgeführt werden"
                                =>  .USER << "fehlerhaftes Kommando in der Liste"
                                    .{keine Kommandos ausgeführt}          // Transaktionsgesichert
                            = "Alle korrekt"
                                =>  .AlleKommandosSequentiellBearbeiten
                                        ---@KommandoAusführen << KommandoListe.Kommando.{Alle nacheinander}

!@KommandoAusführen
    .$kdo <- EXTERN.{einKommando}
    =>  .{$kdo ausführen}
        .{Erfolg ins Log schreiben} 

Wenn im Fenster WnEditorFenster ein einzelnes Kommando selektiert wurde, dann wird WnEditorFenster.Selektion als Kommando ausgeführt. Wenn die Selektion mehrere Kommandos umfasst, dann wird der selektierte Text über einen Verweis namens KommandoListe referenziert und neu interpretiert als geordnete Liste von Kommandos. Diese Liste wird anschließend mehrfach durch Filter bearbeitet. Die Reihenfolge wird dabei explizit vorgeschrieben, wenn sie relevant ist wie in KommandoListe.Kommando.{Alle nacheinander}.

Die Kommando-Unteraspekte von KommandoListe sind nur über diesen Verweis zugänglich, sie werden nicht Unteraspekte von Selektion, obwohl Selektion und KommandoListe wie bei jedem Verweis Namen für denselben Aspekt sind. Ein Zugriff der Art WnEditorFenster.Selektion.Kommando ist also nicht möglich.

Über einen Unteraspekt einer Interpretation kann ein referenzierter Aspekt gelesen, bearbeitet oder verändert werden. Es wäre im Beispiel Kommandofenster möglich, ein weiteres Kommando zur KommandoListe hinzuzufügen, der Inhalt der Selektion würde sich dadurch ändern.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Aktion @

Siehe auch: Sprachelemente

Aspekte aus einem Aktivitätsblock können als Aktion in einen eigenen Definitionsblock ausgelagert werden. Die entstandene Aktion erhält einen Namen, und unter diesem Namen kann der ursprüngliche Aktivitätsblock die Aktion nutzen und auf die entfernten Aspekte Bezug nehmen. Die Nutzung der Aktion in einem Aktivitätsblock ergänzt diesen nutzenden Aktivitätsblock um die Aspekte der Aktion.

Eine Aktion kann nur in einem eigenen Definitionsblock beschrieben werden, niemals als Unteraspekt in einer Teile-Beziehung. Die Markierung als Aktion @ wird sowohl im Kopfaspekt des Definitionsblocks, als auch bei der nutzenden Referenz verwendet. Die Verwendung der Markierung ist optional.

Im nachfolgenden Beispiel Verzeichnis erstellen kann aus einem Fenster ein neues Verzeichnis erzeugt werden. Die Wirkungen werden nicht direkt im Aktivitätsblock von WnVerzeichnisErstellen.BtAnlegen beschrieben, was möglich wäre, sondern in Aktionen ausgelagert. Dieses Produkt liefert einen Rückgabewert an einen unbekannten Nutzer des Produkts, damit dieser in geeigneter Weise auf Erfolg oder Misserfolg reagieren kann.


Beispiel einer Tango-Spezifikation: Verzeichnis erstellen
!#WnVerzeichnisErstellen
    .TxAktuellesVerzeichnis <- DIR.{aktuelles Verzeichnis cwd}
    .EtNeuesVerzeichnis : [ LEER | FormatFalsch | _relativerPfad | _absoluterPfad ]
    .+BtAnlegen
        =>  .@VerzeichnisPrüfenUndAnlegen
    .+BtSchließen
        =>  .WnVerzeichnisErstellen.CLOSE
            .^"NOP, kein Verzeichnis erstellt"

!@VerzeichnisPrüfenUndAnlegen
    .$verzIst <- WnVerzeichnisErstellen.TxAktuellesVerzeichnis
    =>  .$verzNeu <- WnVerzeichnisErstellen.EtNeuesVerzeichnis
        .? verzNeu =
            = LEER
                =>  .BEEP
            = "Untaugliches Format für Verzeichnis"
                =>  .USER << "Format falsch"
            = _relativerPfad
                =>  .@JetztAnlegen << "Pfad aus $verzIst und $verzNeu"
            = _absoluterPfad
                =>  @JetztAnlegen << $verzNeu

!@JetztAnlegen
    .$absVerzeichnis << EXTERN.{absolutes Verzeichnis}
    =>  .{Verzeichnis $absVerzeichnis anlegen} =
            = "OK, erfolgreich angelegt"
                =>  .WnVerzeichnisErstellen.CLOSE
                    .^"OK, Verzeichnis wurde erstellt"    // einfach setzen, kein Durchreichen nach oben7)
            = "Verzeichnis existiert schon"
                =>  .USER << "Verzeichnis existiert schon"
                    .WnVerzeichnisErstellen.EtNeuesVerzeichnis.FOCUS
            = "irgendein Fehler beim Anlegen"
                =>  .USER << "Problem beim Anlegen des Verzeichnisses"
                    .WnVerzeichnisErstellen.EtNeuesVerzeichnis.FOCUS

Die Aspekte des Aktivitätsblocks von WnVerzeichnisErstellen.BtAnlegen wurden in die Aktion @VerzeichnisPrüfenUndAnlegen verschoben, sie sind damit Teil eines anderen Definitionsblocks und gehören nicht mehr zum Kontext von WnVerzeichnisErstellen. Aus der Aktion @VerzeichnisPrüfenUndAnlegen werden Aspekte von WnVerzeichnisErstellen über absolute Pfade referenziert. Diese Referenzen werden in der Aktion durch zwei Verweise abgekürzt, davon wird einer vor und einer im Aktivitätsblock definiert. Beide Verweise gehören zum Kontext der Aktion und stehen in ihrem Aktivitätsblock zur Verfügung. Von außerhalb der Aktion ist nur der Verweis $VerzeichnisPrüfenUndAnlegen.verzIst sichtbar, denn in einen Aktivitätsblock hinein kann von außen nicht referenziert werden.

Jede Aktion kann neben dem Aktivitätsblock weitere Aspekte als Unteraspekte halten, wie $VerzeichnisPrüfenUndAnlegen.verzIst im Beispiel oben. Grundsätzlich sind Aktionen ohne Aktivitätsblock möglich, z.B. wenn die Wirkungen als allgemeine formlose Beschreibung notiert sind.

Die Aktion @JetztAnlegen wird an zwei Stellen in @VerzeichnisPrüfenUndAnlegen genutzt. Hier wird durch Nutzung einer Aktion statt der expliziten Niederschrift der Wirkungen angedeutet, dass aus Sicht des Benutzers beide Male etwas Ähnliches passieren soll. Ob beide Fälle in der Implementierung tatsächlich in dieselbe Prozedur münden, kann und muss an dieser Stelle nicht entschieden werden.

In @JetztAnlegen wird durch Zugriff über absolute Pfade das Fenster #WnVerzeichnisErstellen geschlossen, und der Zustand von WnVerzeichnisErstellen.EtNeuesVerzeichnis wird verändert. Der Zugriff auf Aspekte über absolute Pfade ist der übliche Weg, einer Aktion Information von außerhalb zur Verfügung zu stellen oder Zustände irgendwo in der Spezifikation zu verändern.

Information kann auch durch Senden an eine Aktion übermittelt werden. Dies ist sinnvoll, wenn die Aktion an unterschiedliche Nutzungssituationen angepasst werden soll. Nur beim Senden kann die Information bei jeder Nutzung aus einer anderen Quelle stammen. Die Aktion @JetztAnlegen erhält den absoluten Pfad eines neu anzulegenden Verzeichnisses. Dieser Pfad wird in @VerzeichnisPrüfenUndAnlegen auf zwei verschiedenen Wegen generiert und deshalb mittels Senden an @JetztAnlegen übergeben.

Im Beispiel Kommandofenster wird an die Aktion KommandoAusführen das Kommando durch Senden übergeben, die Aktion holt sich diese Information über EXTERN.{einKommando}. Dieser Weg ist notwendig, da die Quelle der Information wahlweise die ganze Selektion oder ein einzelnes Kommando aus der KommandoListe sein kann.

Im Beispiel Verzeichnis erstellen wird ein Rückgabewert an den hier nicht beschriebenen Nutzer geliefert, damit dieser auf durchgeführte Aktivitäten reagieren kann. Der Rückgabewert wird gemäß der Tango-Beschreibungsmethodik an der Stelle notiert, wo er sichtbar wird, in diesem Beispiel dann, wenn das Fenster geschlossen wird. Da das Produkt ein Fenster ist, wäre zu erwarten, dass beim Nutzer ein Ereignis *WnVerzeichnisErstellen.OPEN der Wertlieferant einer Verzweigung sein könnte.

Eine Aktion ist keine Prozedur und keine Funktion. Referenzen auf eine Aktion ersetzen viele Kopien gleichartiger Aspekte in Aktivitätsblöcken und könnten deshalb als Schreibvereinfachung verstanden werden. Die in der Aktion beschriebenen Aspekte erweitern die Liste der Aspekte im nutzenden Aktivitätsblock, es werden also zusätzliche Wirkungen beschrieben, die alternativ auch direkt im nutzenden Aktivitätsblock notiert sein könnten..

Eine Aktion sollte nur in gleichartigen Kontexten genutzt werden, in denen sie die gleiche Wirkung entfaltet. Flexibles, kontextunabhängiges Arbeiten ist das Kriterium guter Prozeduren und Funktionen, aber nicht von Aktionen. Deshalb ist die Referenz aus der Aktion heraus mittels absoluten Pfaden auf andere Aspekte der bevorzugte Weg, auf Information zuzugreifen. Das Senden von Information bei der Nutzung oder die Kommunikation über Rückgabewerte sollte soweit möglich vermieden werden.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Rückgabewert^

Ein Rückgabewert kann nur innerhalb eines Aktivitätsblocks definiert werden. Ein Nutzer, der einen Vorgang anstößt, erhält die Möglichkeit, auf das Ergebnis in geeigneter Weise zu reagieren, insbesondere auf Erfolg und Misserfolg von Aktivitäten. Der Aktivitätsblock, der den Rückgabewert beschreibt, weiß nicht, wer der Nutzer des Rückgabewertes ist.

Ein Rückgabewert wird mit einem führenden ^ markiert. Er wird an beliebiger Stelle in einem Aktivitätsblock beschrieben, d.h. er muss nicht der letzte Aspekt in einem Aktivitätsblock sein, und er hat keine Auswirkung auf nachfolgende Aspekte in diesem Aktivitätsblock. Werden mehrere unterschiedliche Rückgabewerte beschrieben, die gleichzeitig oder nacheinander wirksam werden, z.B. in geschachtelten Aktivitätsblöcken, so ist die Spezifikation fehlerhaft. Es gibt keine Regel, nach der ein Rückgabewert einen anderen Rückgabewert ersetzen könnte.

Werden Rückgabewerte vom übergeordneten Nutzer verwendet, so impliziert dies eine Reihenfolge und damit eine synchrone Bearbeitung, denn der Aktivitätsblock des Nutzers kann erst vollständig bearbeitet werden, wenn der Rückgabewert zur Verfügung gestellt wird. Dies kann als Implementierungsvorgabe interpretiert werden, obwohl streng genommen nur die Liste der Wirkungen des nutzenden Aktivitätsblocks erweitert wird.8)

Im Beispiel Telefonieren-Protokoll kann der Aktivitätsblock von +IchRufeAn erst bearbeitet werden, wenn das Ergebnis der Aktion @AmtsleitungHolen vorliegt. Der Aktivitätsblock von AmtsleitungHolen enthält den Vorgang Telefon.HörerAbnehmen, dessen Erfolg den Rückgabewert beeinflusst. Aus dieser Kausalität folgt die Synchronisierung von Aktion und nutzendem Aktivitätsblock.

Wird ein Rückgabewert in einem tief geschachtelten Aktivitätsblock definiert, so ist er nicht nur der Rückgabewert dieses Aktivitätsblocks, sondern auch aller anderen Aktivitätsblöcke und Aktionen, in die er geschachtelt ist, solange bis er in einem Aktivitätsblock verwendet wird, z.B. in einer Verzweigung. Der Rückgabewert muss also irgendwo "konsumiert" werden, falls nicht wird er als Rückgabewert des gesamten Produkts verwendet. Weil ein Rückgabewert nicht einfach verfällt, muss bereits bei der Definition überlegt werden, wer der Konsument dieses Rückgabewertes sein soll.

Im Beispiel Verzeichnis erstellen wird in @JetztAnlegen der Rückgabewert des Produkts "OK, Verzeichnis wurde erstellt" erzeugt. Die Aktion @JetztAnlegen wird von @VerzeichnisPrüfenUndAnlegen genutzt. Der Rückgabewert wird in dieser Aktion aber nicht verwendet, deshalb wird er zum Rückgabewert von @VerzeichnisPrüfenUndAnlegen und er wird an den nutzenden Aktivitätsblock zu WnVerzeichnisErstellen.BtAnlegen durchgereicht. Auch hier wird der Rückgabewert nicht verwendet, deshalb ist der hier nicht beschriebene Nutzer des Produkts der Empfänger des Rückgabewertes, und der Rückgabewert wird zur Statusmeldung des ganzen Produkts.

Es gibt mehrere Möglichkeiten, wie Information aus einer Aktion an eine andere Stelle der Spezifikation übermittelt werden kann. Diese Wege unterscheiden sich in ihrer prinzipiellen Wirkung und sind deshalb im allgemeinen Fall nicht austauschbar:

Rückgabewerte übermitteln gewöhnlich nur einfache Information wie "OK, Erfolg" oder "NOK, kein Erfolg". Der Nutzer soll entscheiden können, welche weiteren Aktivitätsblöcke abhängig vom Ergebnis relevant sind, er soll nicht mit komplexer Information versorgt werden.

Im Beispiel Verzeichnis erstellen wird nur der Erfolg mit "OK, Verzeichnis wurde erstellt" an den Nutzer gemeldet, obwohl der absolute Pfad des neu erstellten Verzeichnisses informativer wäre.

Rückgabewerte haben einen stark beschreibungstechnischen, weniger einen inhaltlichen Aspekt. Die Verwendung eines Rückgabewertes um Ergebnisse von Berechnungen u.ä. zu übermitteln ist in der Tango-Beschreibungsmethodik möglich, aber im Allgemeinen kein guter Stil. Rückgabewerte sind notwendig,

In der Praxis können Rückgabewerte meist vermieden werden, außer bei der Beschreibung von Kommunikationsprotokollen und anderen sequentiellen Vorgängen, bei denen der synchronisierende Aspekt von tragender Bedeutung ist.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Ereignis *

Siehe auch: Sprachelemente

Ein Ereignis bewirkt Aktivitäten, entweder im Produkt oder in einem externen System. Ereignisse können von anderen Systemen oder vom Produkt erzeugt werden. Ereignisse können parametrisiert sein, so dass ein einzelnes Ereignis einer Menge von konkreten Ereignissen entspricht. Parameter können mit dem Ereignis gesendet werden, sie stehen dann in der EXTERN-Wolke des Empfängers zur Verfügung. Die Markierung eines Aspekts als Ereignis mit * ist optional.

In einer Spezifikation wird nur das Auslösen des Ereignisses, also die Nutzung beschrieben, das Ereignis selbst wird nicht definiert. Beim Empfänger wird ein Ereignis von einem Aktivator entgegengenommen. Durch die Definition von Aktivatoren werden implizit auch die zugehörigen Ereignisse definiert. Ein Ereignis löst sofort asynchrone Aktivitäten beim Empfänger aus, der Auslöser des Ereignisses wartet nicht auf die Beendigung dieser Aktivitäten. Im nachfolgenden Beispiel werden verschiedene Ereignisse ausgelöst:

!#WnMeinFenster
    .+BtDemoBlock
        =>  .*USER.ALARM << "Fahrbahnmarkierung überfahren"
            .*SYSTEM.SHUTDOWN
            .USER.LOGBUCH << "Arbeit erledigt"
            .WnMeinFenster.CLOSE

Beim USER wird ein ALARM ausgelöst, und die Information dazu wird in der EXTERN-Wolke zur Verfügung gestellt. Das SYSTEM.SHUTDOWN-Ereignis braucht keine zusätzlichen Parameter. Im Beispiel ist nicht klar, ob USER.LOGBUCH ein Ereignis ist oder einen Kanal bezeichnet, dies ist offenbar ohne Bedeutung oder einem kundigen Leser ohnehin bekannt. Das terminale Ereignis WnMeinFenster.CLOSE ist nicht als Ereignis markiert, da dieses Terminal und seine Eigenschaften in der Domäne bekannt sind.

Es gibt viele Möglichkeiten, wie Ereignisse entstehen:

Jedes Ereignis gehört zu genau einem Aktivator. Ereignisse, die von außerhalb des Produkts eintreffen, sind in der Tango-Spezifikation nicht beschrieben, es gibt nur die Aktivatoren dafür. In der Tango-Spezifikation muss nicht beschrieben sein, wann und woher ein Aktivator ausgelöst wird, es kann also Aktivatoren geben, die Ereignisse von innerhalb des Produkts entgegennehmen, ohne dass das dazugehörige Ereignis tatsächlich beschrieben ist. Der Detaillierungsgrad der Spezifikation kann frei gewählt werden, und dies ist einer der Freiheitsgrade.

Im Beispiel Index-Detail-Fenster wird der Aktivator WnOverview.LbItemList.thisItem.CHANGED definiert, aber es gibt kein Ereignis dazu in der Spezifikation. In der Domäne ist bekannt, wann das dazugehörige Ereignis ausgelöst wird.

Wird ein Ereignis an ein anderes System außerhalb des Produkts versandt, so wird stillschweigend davon ausgegangen, dass im anderen System ein entsprechender Aktivator existiert. Dies wird formal kenntlich gemacht mit einem terminalen Namen für das andere System, z.B. USER oder SYSTEM. Alle Unteraspekte des Terminals, und damit auch die Aktivatoren, werden als vorhanden vorausgesetzt, wie bereits beschrieben.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Aktivator +

Siehe auch: Sprachelemente

Ereignisse werden an Aktivatoren entgegengenommen. Die Folgen eines Ereignisses werden im Aktivitätsblock des Aktivators beschrieben. Ein Aktivator kann keinen oder genau einen Aktivitätsblock als Unteraspekt halten. Wenn kein Aktivitätsblock angegeben ist, dann bedeutet dies, dass die eintretenden Wirkungen nicht beschrieben sind, es soll nicht bedeuten, dass der Aktivator funktionslos wäre. Die Markierung eines Aspekts als Aktivator mit + ist optional.

Aktivatoren sind die einzige Möglichkeit, auf Ereignisse zu reagieren. Für jedes Ereignis, auf welches das Produkt reagieren soll, muss deshalb ein Aktivator definiert werden. Ein Aktivator ist für genau ein bestimmtes Ereignis verantwortlich, dieses Ereignis kann parametrisiert sein und beliebig oft eintreten. Das Ereignis und der Aktivator haben denselben Namen und können deshalb einander eindeutig zugeordnet werden. Ein Aktivator kann auch formlos beschrieben werden, dies ist im Allgemeinen nur dann sinnvoll, wenn das Ereignis zu diesem Aktivator in der Spezifikation nirgends ausgelöst wird, denn ohne Identität könnte die Zuordnung von Ereignis und Aktivator schwierig werden.

Im nachfolgenden Beispiel wird der Ziffernblock eines Faxgerätes nicht als zehn Aktivatoren für zehn Ereignisse 0 bis 9 beschrieben, sondern als Aktivator, der auf ein parametrisiertes Ereignis reagiert:

!#FaxBedienpanel
    .TxFaxnummer : [ LEER | "Ziffernfolge"]
    .+BtZiffernblock 
        =>  .TxFaxnummer.{Hinten anhängen} << {getippte Ziffer 0..9}
    .+BtBackspace 
        =>  .?TxFaxnummer =
                = LEER
                    =>  .NOP
                = "Ziffernfolge"
                    =>  .TxFaxnummer.{letzte Ziffer entfernen}
    .BtAllesLöschen              // Stop-Knopf, solange nur Zifferneingabe läuft 
        .{Aktiv nur während Zifferneingabe}
        =>  .TxFaxnummer := LEER

Die Bedienung des Ziffernblocks löst den Aktivator FaxBedienpanel.BtZiffernblock aus, der seinerseits den Aktivator FaxBedienpanel.TxFaxnummer.{Hinten anhängen} auslöst und die eingetippte Ziffer versendet. Die terminalen Aktivatoren {Hinten anhängen} und {letzte Ziffer entfernen} sind nicht explizit als Unteraspekt von TxFaxnummer definiert.

Der Bedienknopf BtAllesLöschen ist nicht explizit als Aktivator gekennzeichnet, er ist aber über seinen Spezialisierungsprefix als solcher erkennbar. Dieser Aktivator hat neben seinem Aktivitätsblock einen weiteren Unteraspekt, der eine Aussage über die Bedienbarkeit dieses Aktivators macht. Ein Ereignis kann nur entgegengenommen werden, wenn der Aktivator aktiv ist, andernfalls wird das Ereignis weggeworfen. Wenn Ereignisse gespeichert werden sollen, z.B. in einer Warteschlange, dann müsste dies explizit beschrieben werden. Die ganze Faxnummer wird gelöscht, wenn während der Zahleneingabe die Stop-Taste gedrückt wird. In anderen Betriebszuständen hat die Stop-Taste möglicherweise eine andere Funktion, die nicht Gegenstand dieser Spezifikation ist.

Die beschriebenen Aktivatoren des Faxpanels stehen mit der Eingabe der Faxnummer in engem Zusammenhang, deshalb wäre eine stärker wirkungsorientierte Beschreibung denkbar, in der die Aktivatoren als Teil eines Eingabetextfeldes präsentiert werden:


Beispiel einer Tango-Spezifikation: Fax bedienen
!#FaxBedienpanel
    .EtFaxnummer : [ LEER | "Ziffernfolge" ]
        .+BtZiffernblock                     // hier stecken die zehn Tasten drin
        .+BtBackspace
            => {falls vorhanden, letzte Ziffer löschen}
        .+BtAllesLöschen                             // der große rote Stop-Knopf
            .{Aktiv wenn Ziffern eingegeben werden} 
            =>  .EtFaxnummer := LEER

Das Eingabetextfeld EtFaxnummer impliziert, dass mit dem Ziffernblock dieses Feld gefüllt werden kann. Der Aktivator BtZiffernblock könnte auch als Terminal formuliert sein, weil dessen Wirkung in der Domäne bekannt ist..

Dasselbe Ereignis wird im Fall des Ziffernblocks mit zehn verschiedenen Tasten ausgelöst. Es kann in der Spezifikation von Bedeutung sein, die verschiedenen Wege zum gleichen Ziel explizit niederzuschreiben. Dies geschieht, indem Aktivatoren, die dasselbe Ereignis auslösen, zu einem Alias zusammengefasst werden. Ein Alias wird genauso verwendet wie ein Aktivator.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Alias ++

Siehe auch: Sprachelemente

Ein Alias wird verwendet, um alle Wege aufzuzeigen, die zum gleichen Ziel führen. Aus Sicht des Produkts ist egal, welcher der Wege beschritten wird, die Wirkung ist immer dieselbe. Die Zusammenfassung alternativer Wege vermeidet unnötige Doppelbeschreibungen in der Spezifikation. Ein Alias wird mit doppelten Pluszeichen ++ markiert, diese Markierung ist optional.

Die Definition eines Alias erfolgt in einem eigenen Definitionsblock. Der Name des Alias kann auch ein Pfad sein, damit werden mögliche Namenskonflikte vermieden. Ein Alias kann überall dort verwendet werden, wo ein Aktivator stehen könnte. Jedem Alias ist genau ein Ereignis zugeordnet. Dieses Ereignis wird wie üblich mit * markiert.

Wirkungen sind gleich, wenn sie mit einem identischen Aktivitätsblock beschrieben werden können. Dies ist zwingende Voraussetzung für die Definition eines Alias.

Der Ziffernblock eines Faxgerätes kann mit einem einzigen Aktivator beschrieben werden, da immer dasselbe Ereignis ausgelöst wird, nur unterschiedlich parametrisiert. Die Tasten könnten in einer Alias-Definition zusammengefasst werden:

!#FaxBedienpanel
    .TxFaxnummer : [ LEER | "Ziffernfolge"]
    .++BtZiffer
        =>  .{Ziffer 0..9 an Inhalt von TxFaxnummer anhängen}
    ... 

//
//  A L I A S
//

!++BtZiffer          // Alias für alle Zifferntasten, Wirkung ist gleich
    .+BtZiffer0
    .+BtZiffer1
    ...              // explizit aufführen wäre besser als Ellipse
    .+BtZiffer9

Es ist üblich, Alias-Definitionen in einen eigenen Bereich der Spezifikation zusammenzufassen, der wie im Beispiel oben mit ALIAS überschrieben ist.

Die Beschreibung alternativer Wege zum Aufruf von Menüpunkten ist eine typische Situation, in der ein Alias verwendet wird:

!++DateiÖffnen
    .+ MenüDatei--Öffnen                // Maus-Auswahl über Menüpunkt Datei
    .+ ALT-D--F                         // Menüwahl durch Tastaturkommandos
    .+ ImÖffnen                         // Auswahl über die Werkzeugleiste
    .+ CTRL-O                           // Direktwahl

Ein direktes Anwählen der Datei aus der Liste zuletzt geöffneter Dateien hätte zwar dasselbe Ergebnis, aber dieser Weg führt zu einer anderen Bedienungsabfolge und kann deshalb nicht in diesen Alias eingeschlossen werden.

Ein Alias dient ausschließlich zum Zusammenfassen von Aktivatoren. Andere Aspekte, Vorbedingungen oder Verzweigungen sind in einem Alias-Definitionsblock nicht erlaubt. Aktivatoren können nur zu einem Alias zusammengefasst werden, wenn sie dasselbe Ereignis entgegennehmen und identische Aktivitätsblöcke enthalten würden.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Container #

Siehe auch: Sprachelemente

Ein Container ist ein Aspekt, der mehrere Aspekte zu einer Einheit zusammenfasst. Eine Markierung mit # als Container ist optional und erfolgt nur, wenn dieser Aspekt in der Domäne eine besondere Bedeutung hat. Die wesentliche Verwendung ist die Kennzeichnung von Schnittstellen zwischen dem Produkt und anderen Systemen oder zu Menschen, z.B. das Fenster einer Bedienoberfläche. Die Zusammenfassung von Aspekten wird durch die Teile-Beziehung allein bereits vollständig beschrieben.

Das nachfolgende Beispiel zeigt ein Frameset, in dem ein Fenster weitere untergeordnete Fenster enthält:


Beispiel einer Tango-Spezifikation: Homepage
!#WnEinFrameSet
    .+OPEN
        =>  .WnInhalt := {Auswahlliste mit Impressum, Produkte, Service}
            .WnText := "Hallo, schön dass sie da sind"
    .#WnNavigation
        .TxImpressum := "Impressum"
            .+CLICK
                =>  .{Extra-Fenster mit dem Impressum}
        .+TxProdukte := "Produkte"
            .+CLICK        
                =>  .WnInhalt := {Produktliste}       
                    .WnText := {Produkt-Auswahlseite} 
        .+TxService := "Service"
            .+CLICK
                =>  .WnInhalt := {Serviceübersicht}
                    .WnText := {Kurzinfo}
    .#WnInhalt
    .#WnText
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Eigenschaft §

Siehe auch: Konzept Sprachelemente

Aspekte, die nicht zeitlich oder örtlich lokalisierbar sind, werden als Eigenschaft bezeichnet im Gegensatz zu Elementen, die immer lokalisiert sind. Eigenschaften sind immer gültig. Die Markierung als Eigenschaft mit § ist optional.

Eine Eigenschaftsmarkierung wird hauptsächlich gesetzt, um zu kennzeichnen, dass dieser Aspekt nicht ein Element beschreibt. Die wichtigste Funktion dieser Markierung ist also die Abgrenzung. Die Markierung von Definitionsblöcken hilft bei der schnellen Einordnung dieser Blöcke und verbessert die Lesbarkeit:

!§TabWirkung
    .{TAB verlässt das aktuell bearbeitete Element und geht zum geografisch nachfolgenden}
    .{alle Elemente außer TxMeldung sind mit TAB erreichbar}

In strukturierten Zuständen ist ein Unteraspekt normalerweise ein geschachtelter Zustand. Andere Aspekte wie Aktivatoren oder Eigenschaften werden als solche markiert, um Missverständnisse auszuschließen:

!#WnOverview
    .$LbItemList
        ...Item
            .MoreInfo
                .§{kommt aus einer extra Datei, nicht aus der Datenbank}
                .+RemoveInfo
                    =>  {Zusatzinfo wird entfernt, das Item selbst bleibt}
            .+RemoveItem
                =>  {Das Item und die Zusatzinfo werden entfernt.}
        .SELECTION : [ "" | _LbItemList.Item ] 

Als Unteraspekt des Zustands LbItemListe ist jedes Item selbst ein Zustand, und ebenso dessen Unteraspekt MoreInfo. Zu MoreInfo ist eine erläuternde Eigenschaft sowie ein Aktivator beschrieben.9) Die Markierungen dieser Unteraspekte stellen klar, dass dies keine Unterzustände sind.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Zustand  $

Siehe auch:  Prinzipien 

Ein Zustand ist ein lokalisierbarer Teil des Gesamtzustands eines Produkts. Die Markierung eines Aspekts als Zustand durch $ ist optional. Die Verfeinerung eines Zustands mit einer Teile-Beziehung beschreibt eine Datenstruktur. Eine datenbankähnliche Struktur entsteht, wenn in Teile-Beziehungen Listen vorkommen. Die Beschreibung von Datenstrukturen orientiert sich an der Nutzung der Daten in der Spezifikation des Produkts, sie trifft keine Aussage darüber, wie diese Datenstruktur tatsächlich implementiert wird.

!$TeilnehmerListe
    ...Teilnehmer
        ...Vorname : _String
        .Familienname : _String
        .GeborenAm : _Datum
        .Adresse
            .StraßeHausnummer : _String
            .Wohnort : _String
            .PLZ : _String

Zustände können Aktivatoren und andere Arten von Aspekten als Unteraspekte halten. Aktivatoren können genutzt werden, um auf Zustandsänderungen automatisch zu reagieren, oder um von außen Veränderungen am Zustand vorzunehmen. Im folgenden Beispiel wird der USER über eine Änderung des Zustands informiert:

    .$letzterZugriff
        .Tag : _Datum
        .Uhrzeit : _Uhrzeit
        .+CHANGED 
            =>  .USER << "letzter Zugriff wurde aktualisiert"

In vielen Aspekten ist implizit ein Zustand enthalten, z.B. in Eingabetextfeldern. Mit einer Wertzuweisung oder einem Verweis kann auf diesen Teil des Aspekts zugegriffen werden. Die Reduzierung eines Aspekts auf diejenigen Teile, die in der jeweiligen Situation relevant sind, geschieht implizit, wobei die Eindeutigkeit in der Verantwortung der Domäne liegt. In unklaren Fällen kann durch Unteraspekte klargestellt werden, mit welchen Teilen eines Aspekts gerade gearbeitet werden soll.

!WnMeinFenster 
    .EtEineEingabe
    .+BtZuweisungen 
        =>  .$Inhalt1 := WnMeinFenster.EtEineEingabe
            .$Inhalt2 := WnMeinFenster.EtEineEingabe.INHALT
            .$Inhalt3 := $WnMeinFenster.EtEineEingabe

Die Wertzuweisung an $Inhalt1 ist möglich unter der Voraussetzung, dass in der Domäne bekannt ist, welcher Teilzustand des Eingabetextfeldes hier verwendet wird. Die Zuweisung an $Inhalt2 nutzt eine detailliertere Beschreibung des verwendeten Unteraspekts. Eine Markierung an $WnMeinFenster.EtEineEingabe als Zustand wie bei der Wertzuweisung an $Inhalt3 ist möglich, bringt aber keine zusätzliche Information gegenüber der Zuweisung an $Inhalt1.

Die vielfältigen Möglichkeiten zur Definition und Bearbeitung von Zuständen werden in einem späteren Kapitel ausführlich erläutert.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Typ _

Ein Typ beschreibt Eigenschaften eines Aspekts. Er wird verwendet, um

Ein Typ beschreibt kein Element, sondern eine Sammlung von Eigenschaften. Die Typ-Markierung _ ist optional, sie kann entfallen, wenn klar ist, dass Eigenschaften gemeint sind, und nicht ein bestimmter Aspekt. Es gibt verschiedene Möglichkeiten, Eigenschaften eines Typs festzulegen:

Eine Typ-Markierung wird gewöhnlich mit dem unbestimmten Artikel gelesen, im nachfolgenden Beispiel als "ein Datum", "ein String" usw.


Beispiel einer Tango-Spezifikation: Buchführungs-Datenmodell
!$BuchungListe
    ...Buchung
        .Buchungstag : _Datum                    // Datum
        .Wertstellung : Datum                    // Typ ohne Typ-Markierung
        .Buchungstext : _STRING                  // String, als terminaler Typ notiert
        .vonKonto : _Konto                       // ein Konto
        .anKonto : _Konto
        .Betrag : _20-2Zahl                      // eine fest formatierte Zahl
        .verbundeneBuchungListe : [ LEER | LEER.NICHT ]    // leer oder nicht
            ...verbundeneBuchung : _BuchungListe.Buchung  // eine andere Buchung
                .{verweist nicht auf sich selbst}
                .{Buchung muss existieren}

!_Konto
    .Kontonummer : _{5stellig mit führenden Nullen}
    .Bezeichnung : _STRING

Der Typ _Datum wird als bekannt vorausgesetzt und nicht weiter beschrieben. Bei der Beschreibung von Wertstellung wird auf die Typmarkierung verzichtet in der Annahme, dass Datum ein allgemein bekannter Typ ist. Der Typ _STRING ist terminal notiert, dies wäre für den Typ 20-2Zahl ebenfalls nützlich um klar zu stellen, dass dieser Typ in der Spezifikation nicht detaillierter beschrieben wird. Der Typ _Konto wird in einem eigenen Definitionsblock verfeinert. Die Kontonummer darin ist formlos beschrieben, wobei die Kennzeichnung der formlosen Beschreibung als Typ optional ist.

Jede Buchung kann, muss aber nicht auf andere Buchungen verweisen, die Inhaltsbeschreibung von verbundeneBuchung verweist auf Einträge in der hier beschriebenen BuchungListe. Einschränkungen sind als Unteraspekte hinzugefügt, in diesem Fall sind Selbstreferenzen verboten, und der Verweis kann nur auf eine Buchung erfolgen, die in der Liste BuchungListe tatsächlich vorhanden ist.

In einer Verzweigung kann gegen einen Typ getestet werden:

!@TestePrimzahl
    .$zahl <- EXTERN.{dieseZahl}
    =>  .?zahl = 
            = _PRIMZAHL
                =>  .USER << "$zahl ist eine Primzahl"
            = _PRIMZAHL.NOT
                =>  .USER << "$zahl ist keine Primzahl"

Ein Typ kann auch in einer Wertzuweisung verwendet werden. Im folgenden Beispiel muss explizit erwähnt werden, dass die Zahl eine Zufallszahl sein soll, denn andernfalls wäre eine Zuweisung von "0" bei jeder Knopfbetätigung ebenfalls akzeptabel:10)

!$EineZahl

!+BtSetzeZufallszahl
    =>  .EineZahl := _INTEGER
            .{verwende zufällige Zahl}

Wenn Typmarkierungen mit anderen Markierungen kombiniert werden, die den Zweck des Aspekts beschreiben, dann ist die Typ-Markierung immer die erste Markierung:

!#WnObjektContainer
    .#Testfenster : _#PrototypFenster

 

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

5.3 Dateien, Blöcke und Kontexte

Ein Block oder Unterblock ist eine Menge von Aspekten, die in der Niederschrift der Spezifikation gleich weit eingerückt sind. Ein Unterblock beschreibt einen übergeordneten Aspekt und ist weiter eingerückt als dieser Aspekt. Ein Unterblock ist beendet, wenn ein Aspekt folgt, der weniger eingerückt ist als dieser Block. Es gibt keine spezielle Kennzeichnung für das Ende eines Blocks.

Die Teile-Beziehung stellt die Verbindung her zwischen dem übergeordneten Aspekt und dem beschreibenden Unterblock. Die Einrückung des Unterblocks ist das Kennzeichen der Teile-Beziehung. Jeder Aspekt kann durch die Teile-Beziehung verfeinert werden, d.h. es wird zusätzliche Information in Form von Unteraspekten hinzugefügt, die den Aspekt erläutern oder ergänzen. In speziellen Situationen, in denen Werte aus syntaktischen Gründen nicht durch einen eingerückten Unterblock beschrieben werden können, wird ein Mehrfachaspekt zur Verfeinerung verwendet.

Definitionsblöcke haben keinen übergeordneten Aspekt, die Tango-Spezifikation selbst besteht aus einer Menge von Definitionsblöcken. Ein Definitionsblock endet, wenn der nächste Definitionsblock beginnt oder wenn die Datei endet. Alle anderen Blöcke sind Unterblöcke und entstehen als Folge einer Teile-Beziehung. Ein Aktivitätsblock ist ein besonderer Unterblock, er beschreibt Wirkungen, die dem übergeordneten Aspekt zugeordnet sind. Unterblöcke, die kein Aktivitätsblock sind, werden als Unteraspektblöcke bezeichnet.

In einem Block mit mehreren Aspekten sind diese Aspekte als Aufzählung oder Sequenz markiert. Jeder dieser Aspekte kann durch einen Unterblock näher beschreiben werden, der durch größere Einrückung gekennzeichnet ist.

Eine Tango-Spezifikation kann aus mehreren Dateien bestehen. Eine fremde Datei erhält einen Namen, so dass die Aspekte dieser Datei mit einem Pfad referenzierbar sind.

Jede Datei bildet einen eigenen Kontext, in dem Namen für Aspekte eindeutig sein müssen, so dass jeder Pfad genau einen Aspekt referenziert. Jeder Definitionsblock und jeder Aktivitätsblock erzeugt einen neuen Kontext, der den übergeordneten Kontext mit einschließt und um eigene Namen erweitert. Dies führt zu einer Schachtelung von Kontexten.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Definitionsblock

Siehe auch: Konzepte Sprachelemente

Ein Definitionsblock wird eingeleitet mit einem führendem Ausrufezeichen !, danach folgt der Kopfaspekt, der in diesem Definitionsblock verfeinert werden soll. Der Kopfaspekt kann als Name, als formlose Beschreibung oder als absoluter Pfad angegeben werden. Ein Definitionsblock endet, wenn der nächste Definitionsblock beginnt oder wenn die Spezifikation oder die Datei endet. Definitionsblöcke können nicht geschachtelt werden.

Die Zeile mit dem Kopfaspekt allein ist bereits ein vollständiger Definitionsblock. In nachfolgenden Beispiel werden zusätzlich mit einer Inhaltsbeschreibung die möglichen Werte des Aspekts beschrieben:

 !$Lampe : ["An" | "Aus" ]

Jeder Definitionsblock definiert seinen eigenen Kontext. Innerhalb dieses Kontextes kann mittels relativer Pfade auf andere Aspekte zugegriffen werden. Für die Referenz auf Aspekte aus anderen Definitionsblöcken wird gewöhnlich ein absoluter Pfad verwendet.

Ein absoluter Pfad als Kopfaspekt muss eindeutig sein, er darf nicht auf einen Aspekt in einem anderen Definitionsblock verweisen. Durch den Pfad wird der Kopfaspekt des Definitionsblocks zum Bestandteil eines fremden Kontextes, nicht jedoch der Definitionsblock selbst. Mit einem Pfad kann auf die Nutzung des Definitionsblocks hingewiesen werden, so weist im nachfolgenden Beispiel der Pfad als Kopfaspekt der Aktion @WnSendeFenster.Blockieren darauf hin, dass diese Aktion im Fenster #WnSendeFenster verwendet wird.

!#WnSendeFenster
    .EtMeldung
    .+BtSenden
        .$Aktiv : [ "Aktiv" | "Inaktiv" ]
    .+BtSendenBlockieren 
        =>  .@Blockieren
    .+BtSendenEntsperren
        =>  .BtSenden.Aktiv := "Aktiv"
    ...

!@WnSendeFenster.Blockieren
    =>  .WnSendeFenster.BtSenden.Aktiv := "Inaktiv"

In WnSendeFenster.BtSendenBlockieren kann die Aktion @WnSendeFenster.Blockieren mit dem relativen Pfad referenziert werden, denn der Kopfaspekt dieser Aktion gehört zum Kontext von #WnSendeFenster.

In der Aktion @WnSendeFenster.Blockieren wird mit einem absoluten Pfad auf den Aspekt WnSendeFenster.BtSenden.Aktiv zugegriffen, dies ist üblich beim Zugriff auf Aspekte eines anderen Definitionsblocks. Trotz des Pfades im Kopfaspekt der Aktion hat der Definitionsblock dieser Aktion seinen eigenen, unabhängigen Kontext. Im Aktivitätsblock von WnSendeFenster.BtSendenEntsperren genügt ein relativer Pfad für die Referenz auf denselben Aspekt.

Eine Tango-Spezifikation besteht aus einer Menge von Definitionsblöcken. Jede zusätzliche Information in der Spezifikation wird durch Verfeinerung der Kopfaspekte von Definitionsblöcken niedergeschrieben. Die Kopfaspekte von Definitionsblöcken sind uneingeschränkt referenzierbar innerhalb einer Datei der Spezifikation. Die Namen der Kopfaspekte sind der Ausgangspunkt aller absoluten Pfade, die in dieser Datei verwendet werden, deshalb müssen die Namen innerhalb der Datei eindeutig sein.

Ein Definitionsblock, dessen Kopfaspekt als formlose Beschreibung notiert ist, kann nicht eindeutig referenziert werden. Solche Definitionsblöcke werden normalerweise nur für eine Sammlung von Eigenschaften verwendet. Referenzen auf Eigenschaften sind unnötig, da Eigenschaften immer und überall gültig sind, die schlechte Referenzierbarkeit hat deshalb keine praktischen Auswirkungen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Unteraspektblock

Siehe auch: Konzepte Sprachelemente

Eine Teile-Beziehung stellt eine Beziehung her zwischen einem Unteraspektblock und einem übergeordneten Aspekt. Der Unteraspektblock wird gegenüber dem übergeordneten Aspekt eingerückt.

Die Interpretation einer Teile-Beziehung kann sich ändern, je nach verfeinertem Aspekt und der Art der hinzugefügten Information, wie bereits im Kapitel Konzepte erläutert wurde. Elemente im Unteraspektblock sind durch die besteht aus-Beziehung mit dem übergeordneten Aspekt verknüpft, Eigenschaften durch hat die Eigenschaft. In einem Unteraspektblock können Elemente und Eigenschaften gemeinsam vorhanden sein.

Ein Unteraspektblock erzeugt keinen neuen Kontext, er gehört zum Kontext des übergeordneten Blocks, dies kann ein Definitionsblock oder ein Aktivitätsblock sein. In einem Unteraspektblock dürfen keine Namen definiert werden, die zu uneindeutigen Pfaden führen. Jeder Aspekt in einem Unteraspektblock kann mit einer Teile-Beziehung weiter verfeinert werden, so dass eine Baumstruktur aus geschachtelten Blöcken entsteht, durch die bei der Konstruktion von Pfaden navigiert wird.

Enthält ein Unteraspektblock mehr als einen Aspekt, so sind die einzelnen Aspekte als Aufzählung oder Sequenz markiert. In einem Block können aufzählungs- und sequenzmarkierte Aspekte gleichzeitig vorhanden sein, dann ist die Reihenfolge nur für die sequenzmarkierten Aspekte untereinander relevant, die aufzählungsmarkierten Aspekte gelten auch aus Sicht der Sequenz immer und gleichzeitig.

Ein Aktivitätsblock ist ein besonderer Aspekt eines Unteraspektblocks. Er beschreibt Wirkungen und er erzeugt einen eigenen Kontext. Ein Aktivitätsblock kann neben anderen Aspekten in einem Unteraspektblock niedergeschrieben sein, er gehört weder zu einer Aufzählung, noch zu einer Sequenz in diesem Unteraspektblock und ist deshalb nur mit dem Wirkungspfeil markiert. Jeder Unteraspektblock kann nur einen einzigen Aktivitätsblock enthalten.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Aktivitätsblock =>

Siehe auch: Konzepte

Durch einen Wirkungspfeil => in einem Unteraspektblock wird ein Aktivitätsblock eingeleitet. Ein Aktivitätsblock enthält eine geordnete oder nicht geordnete Sammlung von Wirkungen, die eintreten müssen, wenn eine Vorbedingung erfüllt ist. Eine Vorbedingung kann sein:

Ein Aktivitätsblock enthält Wirkungen, er beschreibt also Ergebnisse von dynamischen Vorgängen, während alle anderen Blöcke nur statische Aspekte beschreiben wie Elemente oder Eigenschaften. In einem Aktivitätsblock können keine statischen Elemente oder Eigenschaften beschrieben werden, die außerhalb des Aktivitätsblocks sichtbar wären. Statische Aspekte in einem Aktivitätsblock dienen nur der Schreibvereinfachung.

 !#WnFensterUmschalten
    .#WnFenster1
         .Sichtbar : _Boolean
    .#WnFenster2
         .Sichtbar : _Boolean  
    .+BtZeigeFenster1
        =>  .WnFensterUmschalten.WnFenster1.Sichtbar := "Ja, sichtbar"
            .WnFenster2.Sichtbar := "Nein, nicht sichtbar"
            .USER << "akustisches Fensterumschalt-Signal"

Der Aktivitätsblock von BtZeigeFenster1 enthält drei Kriterien, die nach dem Auslösen dieses Knopfes erfüllt sein müssen. Die Aufzählung im Aktivitätsblock ist zu interpretieren als Checkliste, welche Wirkungen durch das Auslösen des Aktivators entstehen.

Es gibt keine Pfade, die von außerhalb in einen Aktivitätsblock hinein verweisen. Aktivitätsblöcke sind abhängig von Vorbedingungen, so ist im Beispiel oben die Checkliste mit den Wirkungen nur dann relevant, wenn WnFensterUmschalten.BtZeigeFenster1 ausgelöst wurde. An irgendeiner anderen Stelle der Spezifikation ist diese Situation gerade nicht gegeben, deshalb ist überall anders der Inhalt des Aktivitätsblocks irrelevant.

Aus einem Aktivitätsblock heraus kann auf andere Aspekte der Spezifikation referenziert werden, sowohl mit relativen wie auch mit absoluten Pfaden. Ein Aktivitätsblock erweitert aus seiner eigenen Sicht den Kontext, in dem er niedergeschrieben wurde um eigene Information und erzeugt damit einen neuen, größeren Kontext. Diese Erweiterung ist eine Einbahnstraße. Der Aktivitätsblock sieht den Kontext des umfassenden Blocks, aber dieser umfassende Block kann nicht in den Aktivitätsblock hineinsehen.

Im Beispiel oben wurde vom Aktivitätsblock aus auf die Sichtbar-Aspekte der Teilfenster zugegriffen, dies ist mit dem absoluten Pfad WnFensterUmschalten.WnFenster1.Sichtbar möglich, aber auch mit dem relativen Pfad WnFenster2.Sichtbar, da der Aktivitätsblock den Kontext des Definitionsblocks zu WnFensterUmschalten kennt und berücksichtigt.

In einem Aktivitätsblock können Wirkungen auf externe Systeme oder auf den Gesamtzustand des Produkts beschrieben werden. Der Aktivitätsblock selbst repräsentiert einen Teil des Gesamtzustands des Produkts, denn er ist nur relevant, wenn eine Kette von Vorbedingungen erfüllt wurden. Jede Vorbedingung in dieser Kette wird repräsentiert durch einen Aktivitätsblock, der durch eben diese zusätzliche Vorbedingung relevant wurde, so dass die darin beschriebenen Wirkungen eintreten. Die erste Vorbedingung in der Kette ist immer, dass ein Ereignis von einem Aktivator entgegengenommen wird.

Aktivitätsblöcke können Abläufe beschreiben, bei denen die Reihenfolge der einzelnen Schritte relevant ist. Wenn die nächsten Schritte von Vorbedingungen abhängen, dann wird dieser Ablauf durch eine Verzweigung beschrieben, durch die weitere Aktivitätsblöcke entstehen, die den nächsten Schritt beschreiben. Im Beispiel Telefonieren-Protokoll ist die Aktion @AmtsleitungHolen so konstruiert:

!@AmtsleitungHolen   
    =>  .?Telefon.HörerAbnehmen =
            = "Amtsleitung gekriegt"
                =>  .^"OK, Leitung ist da"
            = "Keine Amtsleitung, Telefon tot"
                =>  ?Telefon.{Mehrmals auf die Gabel tippen} = 
                        = "Amtsleitung gekriegt"
                            =>  .^"OK, Leitung ist da"
                        = "Immer noch nix" 
                            =>  .^"NOK, Telefon tot"

Das Gabeltippen ist nur notwendig, wenn der Anrufer keine Amtsleitung erhalten hat. Der nächste Schritt hängt also davon ab, welchen Zustand das Telefon einnimmt, wenn der Hörer abgenommen wurde.

Wenn ein Schritt nicht vom Ergebnis des letzten Schrittes abhängt, dann wird die geordnete Abfolge der Schritte durch eine Sequenz beschrieben. Im Beispiel Telefonieren-Protokoll wird auf diese Weise das Sprechen auf den Anrufbeantworter notiert:

                        =>  .? {Motivation und Worte vorhanden} =
                                = "Ja, ich will mich verewigen"
                                    =>  -{Ansage und Pieps abwarten}
                                        -{Spruch aufsagen}
                                        -Telefon.HörerAuflegen

Die möglichen Fehlerfälle bei den einzelnen beschriebenen Schritten werden hier nicht berücksichtigt, z.B. dass die Ansage lauten könnte "Das Band ist voll", oder dass der Sprecher zu lange überlegt und die Gegenseite auflegt. Der Erfolg jedes Schritts wird bei der Nutzung einer Sequenz implizit vorausgesetzt.

Die Aufzählung von Wirkungen in einem Aktivitätsblock trifft keine Aussage, in welcher Reihenfolge die Wirkungen eintreten, in welcher Reihenfolge die dazu gehörigen Prozesse gestartet werden oder wie lange die Bearbeitung dauert. Die einzige Aussage ist, dass zu irgendeinem Zeitpunkt alle Wirkungen eingetreten sind, und dies ist der Moment, an dem die Checkliste abgearbeitet wird.

Wirkungen, die in einer bestimmten Reihenfolge eintreten müssen, werden mit einer Sequenz beschrieben und in dieser Reihenfolge geprüft. Die Sequenz beschreibt nur die Reihenfolge der Wirkungen, sie macht keine Aussagen über die Implementierung wie parallele oder sequentiell ablaufende Prozesse. Zeitliche Abstände zwischen den einzelnen Sequenzschritten oder Manipulationen am System ("Weiter mit <Return>") werden falls notwendig in den einzelnen Schritten der Sequenz mit beschrieben. Um die Implementierung des Produkts nicht unnötig einzuschränken, sollte die Beschreibung von Wirkungen in Aktivitätsblöcken möglichst mit Aufzählungen statt Sequenzen erfolgen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Datei

Siehe auch: Konzepte

Eine Tango-Spezifikation kann auf mehrere Dateien aufgeteilt sein. Jede Datei kann mit einem Include-Definitionsblock in jede andere eingebunden werden, dabei ist mehrfaches oder zyklisches Einbinden möglich. Die Reihenfolge von Definitionsblöcken spielt in einer Tango-Spezifikation keine Rolle, deshalb können Dateien mit weiteren Spezifikationsteilen an jeder beliebigen Stelle eingebunden werden. Ebenso ist ohne Bedeutung, wenn das Einbinden der Datei erst nach der Nutzung des Inhalts erfolgt. Es ist üblich, dass Include-Definitionsblöcke am Anfang einer Datei stehen.

Der Name, unter dem der Inhalt der fremden Datei referenziert werden kann, wird durch den Kopfaspekt des Include-Definitionsblocks bestimmt, markiert mit einem führenden Ausrufezeichen !, so dass der Definitionsblock mit zwei Ausrufezeichen !! beginnt. Der nachfolgende Verweis enthält den Dateinamen und gegebenenfalls den Verzeichnispfad der fremden Datei als formlose Wertbeschreibung.

Auf einen Aspekt der anderen Datei kann zugegriffen werden über einen Pfad, dessen erstes Element der Name des Kopfaspekts des Include-Definitionsblocks ist.

!! GUImüller <- "mueller-modul1.txt"  

!#WnDiesesFenster
    .ÄnderungsStatus <- $GUImüller.WnDetail.EtText.MODIFIED

Jede Datei bildet ihren eigenen Kontext. Durch das Einbinden der Datei werden die Kontexte der Dateien nicht zusammengeführt. Eine Tango-Spezifikation aus mehreren Dateien ist zusammengesetzt aus mehreren voneinander unabhängigen Kontexten.

Die Arbeit mit getrennten Dateien ist vorteilhaft, wenn eine Spezifikation von mehreren Mitarbeitern erstellt oder bearbeitet werden soll, da die Gefahr von Namenskollisionen entfällt und die Schnittstellen zwischen den Verantwortungsbereichen leicht verwaltet werden können. Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Kontext

Ein Kontext ist ein Namensraum, in dem eindeutige Namen genutzt werden, um über relative Pfade Aspekte zu referenzieren. Kontexte werden ineinander geschachtelt, wenn deren Niederschrift geschachtelt ist. Kontexte entstehen durch

 

Abb 5.1: Geschachtelte Kontexte ähnlich dem Beispiel Taschenrechner. Kontexte von Dateien sind immer voneinander unabhängig, jeder Dateikontext enthält die Kopfaspekte seiner Definitionsblöcke wie z.B. @JetztBerechnen. Der Definitionsblock !#WnKalkulator definiert selbst TxErgebnis und weitere Aspekte, und er schließt den Kontext seiner Datei mit ein. Der Aktivitätsblock zu WnKalkulator.EtWert2.CR betrachtet seinen umfassenden Definitionsblock und die Datei als Beitrag zum Kontext, der Aktivitätsblock zur Abfrage auf WnKalkulator.EtWert1."Leer" kennt auch den Kontext des ihn umfassenden Aktivitätsblocks WnKalkulatorEtWert2.CR. Die Datei daneben entstammt nicht dem Beispiel, sie zeigt die unabhängige Kontextschachtelung.

Die Namen in einem Kontext müssen nicht eindeutig vergeben werden, aber bei der geringsten Gefahr von Mehrdeutigkeit ist die Adressierung über relative Pfade nicht mehr möglich. Unteraspekte desselben übergeordneten Aspekts können niemals gleiche Namen erhalten, in diesem Fall wäre die Spezifikation fehlerhaft. In allen anderen Fällen gleicher Namen können die Aspekte an Hand des absoluten Pfades zum Aspekt unterschieden werden. Es gibt keine Regel, nach der eine "lokale" Definition eines Namens eine "globale" Definition überdecken könnte, wie dies in Programmiersprachen üblich ist.

Im Beispiel Kundenkontakt-Verwaltung ist der Name EtLetzterKontakt im selben Kontext mehrfach verwendet. Dies ist unschädlich, solange der Name nicht als relativer Pfad verwendet wird. Im Beispiel beginnen die relativen Pfade auf die beiden so bezeichneten Aspekte an jeweils eindeutigen Namen als WnTelefon.EtLetzterKontakt und WnHandy.EtLetzterKontakt. Andere Namen wie EtName, EtTelNr und EtHandyNr sind eindeutig und können überall im Beispiel als relative Pfade verwendet werden, etwa als Sendeinformation im Aktivitätsblock zu WnKundenkontaktVerwaltung.BtAnPartnerTelefonmarketingWeitergeben.

Die Schachtelung der Kontexte ergibt sich ausschließlich aus der Niederschrift, nicht aus irgendwelchen Nutzungszusammenhängen.

Im Beispiel Taschenrechner wird die Aktion @JetztBerechnen im Aktivitätsblock von WnKalkulator.EtWert2.CR genutzt, trotzdem sind die Kontexte von WnKalkulator und @JetztBerechnen voneinander unabhängig. Deshalb wird mit absoluten Pfaden von @JetztBerechnen aus auf die Information in @WnKalkulator zugegriffen, z.B. auf WnKalkulator.TxErgebnis. Daran würde sich auch nichts ändern, wenn der Kopfaspekt der Aktion benannt wäre als !@WnKalkulator.JetztBerechnen. Der Pfad am Kopfaspekt ist ein Hinweis auf die Verwendung und er erweitert den Kontext von WnKalkulator um den Namen des Kopfaspekts JetztBerechnen, aber er ändert nichts am Kontext des Unterblocks von JetztBerechnen.

Dasselbe gilt auch für Dateien, deren Spezifikationsteile über einen Include-Definitionsblock zugänglich gemacht werden. Die Kontexte der Dateien bleiben trotzdem voneinander getrennt. Eine Tango-Spezifikation besteht aus mehreren voneinander unabhängigen Kontexten, wenn sie in mehrere Dateien aufgeteilt ist.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

5.4 Zustände beschreiben, ändern und auswerten

Ein Zustand ist ein explizit sichtbar gemachter Teil des Gesamtzustands des Produkts. Die explizite Darstellung erlaubt, den Zweck oder das Verhalten des Zustands zu beschreiben. Wird ein Zustand mit einem Namen versehen, so kann aufgezeigt werden, an welchen unterschiedlichen Stellen im Produkt der Zustand Wirkung entfaltet, so dass Zusammenhänge im Produkt aufgedeckt werden.

Jeder Zustand kann einen oder mehrere Werte aus einer Menge von Werten annehmen. Diese Werte können aufgezählt werden oder ihrer Art nach beschrieben werden durch eine Inhaltsbeschreibung. Die Tango-Beschreibungsmethodik verlangt nicht, dass diese Wertemenge immer beschrieben sein muss. Zur Aufzählung möglicher Werte kann die Auswahlliste genutzt werden, zur Beschreibung der Eigenschaften von Werten ein Typ.

Ein Zustand kann aus mehreren Zuständen zusammengesetzt sein, diese Struktur wird durch die Teile-Beziehung beschrieben. Mit Unteraspekten werden auch Eigenschaften des Zustands notiert, oder es werden Aktivatoren zugeordnet, die entweder auf Ereignisse von außen oder auf Veränderungen des Zustandes reagieren können. Unteraspekte eines Zustands, die selbst keine Zustände sind, sollten mit einer entsprechenden Markierung gekennzeichnet werden.

!$Uhrzeit
    .{wird ständig aktualisiert}   // könnte mit § markiert sein
    .+CHANGED
        =>  .?{aktuelle Uhrzeit} =
                = 10:00Uhr
                    =>  .USER << "Zeit für Brotzeit" 
                = "andere Uhrzeit"
                    =>  .NOP                

Der Zustand $Uhrzeit wird mit einer Eigenschaft näher beschrieben. Verändert sich der Zustand, so wird im Aktivitätsblock des Aktivators +CHANGED geprüft, ob eine Meldung an den USER geschickt werden soll.

Die Struktur eines Zustand entsteht aus einer nutzungsorientierten Sichtweise auf den Zustand, sie trifft keine Aussage über die tatsächliche Implementierung. Ein Zustand kann über einen Verweis an mehreren Stellen der Spezifikation verwendet werden, und durch Interpretation kann derselbe Zustand an verschiedenen Stellen eine unterschiedliche Struktur aufweisen.

Ein Zustand kann in einem Aktivitätsblock über eine Wertzuweisung beschrieben sein, damit wird festgelegt, welchen Wert der Zustand hält zu dem Zeitpunkt, an dem dieser Aktivitätsblock relevant wird. In einem anderen Aktivitätsblock könnte über eine andere Wertzuweisung der Zustand anders beschrieben sein, denn diese Wertzuweisung trifft zeitlich beschränkte Aussagen über den Zustand.

Eine Wertzuweisung außerhalb eines Aktivitätsblocks beschreibt den Zustand einmalig und unveränderlich, dieser Zustand wird zu einer Konstanten. In der Beschreibung des Zustands können auch andere Konstanten einbezogen werden, aber keine Zustände, die sich verändern könnten, Dies wäre ein Fehler der Spezifikation, denn der tatsächliche Wert des einbezogenen Zustands könnte nicht ermittelt werden.

Wird ein Zustand mit einem Verweis beschrieben, dann ist die Beschreibung selbst unveränderlich, aber der Wert des Zustands wird sich ändern, wenn sich der referenzierte Zustand ändert. Die Beschreibung eines Zustands mit einem Verweis ist innerhalb und außerhalb eines Aktivitätsblocks möglich. Die Beschreibung könnte eine Berechnung sein, die auch andere konstante oder veränderliche Zustände mit einbezieht.

In einem Aktivitätsblock kann der Wert eines Zustands durch Senden in eine EXTERN-Wolke gestellt werden, so dass er von anderen Systemen oder an anderer Stelle des Produkts benutzt werden kann. Der Wert eines Zustands wird auch genutzt um in einer Verzweigung oder einer Bedingung zu entscheiden, ob Wirkungen in weiteren Aktivitätsblöcken relevant sind.

Aspekte, die selbst keine Zustände sind, können einen Zustand als Unteraspekt halten, deshalb können auch Aspekte wie z.B. Eingabetextfelder, die erkennbar kein Zustand sind, als Zustände behandelt werden. Solche Aspekte sind durch Konventionen der Domäne in ihren Eigenschaften bestimmt, und diese Konventionen legen fest, welcher Teil dieser Aspekte als Zustand weiterverarbeitet werden kann. Im Fall eines Eingabetextfeldes wird gewöhnlich der aktuell eingegebene Inhalt als Zustand des Aspekts betrachtet.

Zustände werden definiert, wenn sie zur Beschreibung des Produkts notwendig sind, wenn sie also aus Sicht des Benutzers eine Wirkung entfalten. Technisch bedingte Zustände sind Thema der Implementierung und sollten in der Spezifikation vermieden werden. Zustände müssen nicht auf Variablen eines Programms abgebildet werden können, es ist auch ohne Bedeutung, wie kompliziert es in der Praxis ist, den aktuellen Wert des Zustands tatsächlich festzustellen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Wert

Werte beschreiben Zustände. Der aktuelle Wert eines Zustands kann mit einer Wertzuweisung beschrieben werden. Die Werte, die ein Zustand annehmen kann, sind implizit Unteraspekte des Zustands und deshalb über einen Pfad referenzierbar. Werte sind in ihrer Wirkung mit Terminalen vergleichbar, deshalb müssen sie nicht als Unteraspekte des Zustands niedergeschrieben sein, die Existenz der verwendeten Werte wird vorausgesetzt.

Ein Wert ist ein Aspekt, der mit einer allgemeinen formlosen Beschreibung, einer formlosen Wertbeschreibung oder mit einem Namen beschrieben wird. Die Namen von Werten sind Teil des Kontextes und sie müssen grundsätzlich eindeutig sein, wenn mit ihnen ein relativer Pfad beginnen soll. In der Praxis sind Namen von Werten gewöhnlich eindeutig, da durch das nutzende Konstrukt die Zuordnung des Wertes zu seinem Zustand offensichtlich wird. Namen von Werten müssen dann nur mehr innerhalb der Wertemenge eines Zustands eindeutig sein. Probleme können auftreten, wenn Werte und Nicht-Wert-Aspekte in einem Kontext denselben Namen erhalten.

Werte können aus mehreren Aspekten bestehen, die dann als Mehrfachaspekt niedergeschrieben werden. Konvertierung oder Umrechnung von Werten sind domänenspezifisch und werden gewöhlich durch terminale Unteraspekte beschrieben.

!$Familie
    ...Mitglieder

!+BtVieleWerteZuweisen
    =>  .$Familie := (Adam, Eva, Kain, Abel)

!+BtWerteKonvertieren
    =>  .$Sichtbarkeit := "Ja, sichtbar".NOT         // der Wert "Nein, nicht sichtbar"
        .$NegativeZahl := "21".NEGATIV               // der Wert "-21"
        .$Minuten := "1:38 Uhr".{Als Tagesminuten}   // der Wert "98 Minuten"
...

Ein Wert ist an den Zustand gebunden, den er beschreibt. Die Minuten und Stunden einer Uhr werden deshalb durch unterschiedliche Werte beschrieben. TxStunde.11 und TxMinute.11 sind zahlenmäßig gleich, aber trotzdem unterschiedliche Werte, da sie zu unterschiedlichen Zuständen gehören. Wenn die Werte in verschiedenen Zuständen miteinander verglichen werden oder untereinander zugewiesen werden, dann liegt dem eine Konvention der Domäne zu Grunde, dass diese Werte überhaupt vergleichbar sind. Dies kann besonders bei logischen Werten eine durchaus problematische Annahme sein. Um Fehler aus solchen Prämissen zu vermeiden, sollten Werte immer dem Sinn nach beschrieben werden, also nicht nur "Ja", sondern "Ja, ist selektiert", oder "11 Minuten" statt "11", denn damit werden Konvertierungen offensichtlich.

Im nachfolgenden Beispiel wird eine Uhrzeit auf Besonderheiten überprüft:

!#WnUhr
    .TxStunde : "0..23"
    .TxMinute : "0..59"
    +BtFasching
        =>  & TxStunde.11 &            // problemlose Formulierung
                & TxMinute.11
                    =>  USER << "Es ist 11 Uhr 11"
    +BtSchnapszahl
        =>  & {TxStunde = TxMinute}    // "9 Std" = "9 Min", gewagte Behauptung
                => USER << "Stunde ist gleich Minute"

Die Beschreibung zu BtFasching ist unkritisch, denn die Zustände werden auf ihren eigenen Wert 11 geprüft, also "11 Std" und "11 Min". In BtSchnapszahl werden zwei Zustände verglichen. Streng genommen könnten die Werte niemals gleich sein, nur die Konvention der Domäne "Wie interpretiere ich eine Uhr" macht diesen Vergleich möglich. Wer sich nicht auf diese Domänenkonvention verlassen will, verwendet folgende Formulierung, die praktischerweise auch das beschreibt, was eigentlich gemeint ist:

    +BtSchnapszahl
        =>  & {TxStunde.ALSZAHL = TxMinute.ALSZAHL}
                =>  USER << "Stunde ist gleich Minute"

Die Beschreibung eines Wertes muss nicht auf einen bestimmten Wert eingegrenzt werden, es genügt eine Beschreibung der notwendigen Eigenschaften eines möglichen Wertes:

!+BtKomplexeWertbeschreibungen
    =>  .$Zufall := eineZufallszahl
        .$Berechnet := "25 * $Zufall"
        .$AllePositivenUndGeraden := "Menge aller geraden positiven Zahlen"
        .$Auswahl := [ 20 | 25 ]
        .$Collection := (10 , 15)

$Zufall erhält irgendeine Zufallszahl, die Wertbeschreibung gibt nur Auskunft über den Weg zur Ermittlung, nicht den Wert selbst. Der Wert von $Berechnet ist das Ergebnis einer mathematischen Berechnung, die von einem anderen Zustand abhängt. Der Wert von $AllePositivenUndGeraden wird durch seine Eigenschaften beschrieben und umfasst eine große Menge von Zahlen. Der Zustand $Auswahl hält entweder die Zahl 20 oder 25. Der Zustand $Collection kann mehrere Werte aufnehmen, und die Werte werden mit einem Mehrfachaspekt in einer einzigen Wertzuweisung gesetzt.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Inhaltsbeschreibung  :

Mit einer Inhaltsbeschreibung wird festgelegt, welche Werte ein Zustand annehmen kann. Eine Inhaltsbeschreibung ist optional, aber wenn sie vorhanden ist, dann muss sie sämtliche mögliche Werte dieses Zustands umfassen, einschließlich der Möglichkeit, dass der Wert des Zustands undefiniert ist. Eine Inhaltsbeschreibung kann die möglichen Werte aufzählen, die Werte beschreiben oder den Zweck oder die Herkunft des Zustands beschreiben, wenn sich daraus die Werte ableiten lassen.

Eine Inhaltsbeschreibung besteht aus einem Zustand, gefolgt von einem Doppelpunkt : und nachfolgend die Beschreibung der möglichen Werte. Die Beschreibung kann erfolgen als allgemeine formlose Beschreibung, formlose Wertbeschreibung, Auswahlliste, strenge Auswahlliste oder als Typ.

!#WnInhaltDemo
    .$BlinkerAn : _Boolean                          // Beschreibung mit Typ
    .$AutoLäuft : [ Ja | Nein | Hoppelnd | WeißNicht ]  // Beschreibung mit Auswahlliste
    .$Höchstgeschwindigkeit : "1kmh..400kmh"        // formlose Wertbeschreibung
    .$Hubraum : {steht in den Fahrzeugpapieren}     // allgemeine formlose Beschreibung
    .$Passagiere : ( _Integer, "1..5" )             // Mehrfachaspekt
    .$AnzahlLenkräder : 1                           // Einzelwert wirkt als Wertzuweisung

Die Anzahl der Passagiere ist durch einen Mehrfachaspekt beschrieben. Die rechte Seite einer Inhaltsbeschreibung kann nicht durch eine Teile-Beziehung verfeinert werden, mehrere Aspekte an dieser Stelle erfordern deshalb einen Mehrfachaspekt. Alternativ wäre auch eine formlose Beschreibung möglich.

Die Inhaltsbeschreibung sagt, welche Werte ein Zustand annehmen kann, und nicht, welchen Wert er tatsächlich hält. Einzige Ausnahme ist, wenn die Beschreibung nur einen einzigen Wert zulässt, dann wirkt die Inhaltsbeschreibung als Wertzuweisung. Im Beispiel oben wird die AnzahlLenkräder auf 1 gesetzt. Der Wert dieses Zustands kann in der Spezifikation nicht mehr verändert werden.

Wenn ein Zustand einen undefinierten oder gar keinen Wert halten könnte, so ist dies aus Sicht der Inhaltsbeschreibung ein weiterer Wert, der notiert werden muss, da die Inhaltsbeschreibung alle Werte umfasst. Im Beispiel oben kann $AutoLäuft den Wert WeißNicht annehmen, dessen technische Repräsentation der undefinierte Inhalt sein könnte. Wie bei allen Werten wird auch in diesem Fall der Zweck des undefinierten oder leeren Zustands angegeben, und nicht der tatsächliche Wert.

Im Beispiel Buchführungs-Datenmodell kann BuchungListe.Buchung.verbundeneBuchungListe den Wert LEER annehmen, wenn eine Buchung nicht von irgendeiner anderen abhängt. In der zugehörigen Datenbanktabelle VerbundeneBuchung gibt es dann keine Einträge mit dieser Buchung als Primärschlüssel. Diese Implementierung ist unerheblich, wichtig für die Tango-Spezifikation ist, dass solche verbundenen Buchungen optional sind, und dies ist in der Inhaltsbeschreibung vermerkt.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Auswahlliste  [ | ]

Die Auswahlliste beschreibt eine Menge von Aspekten. In einer Inhaltsbeschreibung werden damit die möglichen Werte eines Zustands notiert. In einer Verzweigung oder Bedingung kann geprüft werden, ob ein Zustand einen Wert hält, der in dieser Menge von Werten enthalten ist. In einem Filter beschreibt die Auswahlliste mehrere Aspekte als Alternativen in einem Schritt des Pfades, so dass der Pfad ab hier zwei oder mehr verschiedene Wege einschließt.

Die Auswahlliste ist von eckigen Klammern [ ] eingefasst, die Alternativen sind voneinander durch einen senkrechten Strich | getrennt. Die Alternativen können Aspekte sein, oder Beschreibungen von ein oder mehreren Aspekten. Ein bestimmter Aspekt ist in der Auswahlliste vorhanden, wenn er zu einer der beschriebenen Alternativen passt, er muss nicht explizit in der Auswahlliste vertreten sein.

!AuswahllistenDemo
    .$eineZahl : [0 | _geradeZahl | _Primzahl ]
    .$fehlerstatus : [ keinFehler | Fehler | weißNicht ] 
    .$fehlerursache : [ LEER | _HardwareFehler | _SoftwareFehler | _Unklar ]
    .+BtSetzenDemo
        =>  .eineZahl := 2              // gerade Zahl und Primzahl, ok
            .fehlerstatus := Fehler     // explizit aufgeführter Wert, ok
            .fehlerursache := HardwareZuSchnellFürSoftware   // passt zu irgendeiner Alternative, ok
    .+BtAufgabenVerteilen
        =>  & fehlerstatus.Fehler &
                & fehlerursache.[ _HardwareFehler | _SoftwareFehler ]
                    =>  .PROJEKTLEITER << "Fehler an Verantwortlichen weiterleiten"
                & fehlerursache._Unklar
                    =>  .TESTGRUPPE << "Fehler eingrenzen"
            & fehlerstatus.weißNicht
                =>  .TESTGRUPPE << "Produkt prüfen"
            & fehlerstatus.keinFehler
                =>  .{Schampus kaltstellen}

Die Beschreibung der Aspekte in den Alternativen kann zu Aspektemengen führen, die sich überschneiden. Wenn dies ein Problem wird, z.B. bei der Prüfung von Werten in einer Bedingungskaskade, so können die Aspektemengen in der Auswahlliste disjunkt formuliert werden. Für eine disjunkte Beschreibung von Aspektemengen ist eine strenge Auswahlliste besser geeignet, da durch deren spezielle Lesart das Formulieren disjunkter Mengen einfacher wird.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Strenge Auswahlliste  [ || ]

Eine strenge Auswahlliste beschreibt wie jede Auswahlliste eine Menge von Aspekten, aus denen ein einzelner ausgewählt werden kann. Sind die einzelnen Aspekte explizit angegeben, so ist die strenge Auswahlliste in der Wirkung identisch mit der Auswahlliste. Wenn in der strengen Auswahlliste Aspektemengen als Alternativen beschrieben werden, dann sind diese Mengen disjunkt, d.h. jeder mögliche Aspekt kann einer dieser Alternativen eindeutig zugeordnet werden.

Die strenge Auswahlliste ist von eckigen Klammern eingefasst wie jede Auswahlliste, aber die einzelnen Alternativen sind durch doppelte senkrechte Striche || voneinander getrennt. Jede nachfolgende Alternative setzt implizit voraus, dass keine der vorangehenden Alternativen zutrifft. Die Reihenfolge, in der die Alternativen niedergeschrieben sind, ist also von Bedeutung. Diese Lesart entspricht der Art und Weise, wie in Verzweigungen die einzelnen Alternativen behandelt werden. Auch dort wird die erste zutreffende Alternative gewählt.

Für eine Inhaltsbeschreibung ist der Unterschied zwischen einer Auswahlliste und einer strengen Auswahlliste ohne Bedeutung. Beim Prüfen eines Zustands kann es von Vorteil sein, wenn genau eine Alternative zutrifft, insbesondere, wenn diese Prüfung in einer Bedingungskaskade durchgeführt wird, da ansonsten unerwünscht mehr als eine Bedingung zutreffen könnte.

!FindeTeiler
    .$positiveZahl : [ 1 || _geradeZahl || _Primzahl || _ungeradeZahl ]
    +BtGibTeiler
        =>  & positiveZahl.1
                =>  USER << "Zahl ist 1"
            & positiveZahl._geradeZahl
                =>  USER << "Teiler ist 2"
            & positiveZahl._Primzahl
                =>  USER << "Zahl ist Primzahl"
            & positiveZahl._ungeradeZahl
                =>  USER << "Teiler ist @{sucheTeiler}"

Durch die strenge Auswahlliste in diesem Beispiel wird außer dem Inhalt von $positiveZahl auch noch festgelegt, dass _geradeZahl, _Primzahl und _ungeradeZahl disjunkt sein sollen. Die Definition der Mengen entspricht nicht der üblichen Bedeutung: aus der Reihenfolge ergibt sich, dass 1 und 5 in diesem Sinne keine _ungeradeZahl sind, 2 ist keine _Primzahl. Ohne diese Festlegung in einer strengen Auswahlliste würde mehr als eine Bedingung zutreffen, und der USER würde mehr als eine Meldung gleichzeitig erhalten.

Die Bedingungen im Aktivitätsblock von FindeTeiler.BtGibTeiler könnten beliebig umgestellt werden, da jede Bedingung ein von allen anderen unabhängiger Aspekt ist. Relevant ist in diesem Beispiel die Reihenfolge der Alternativen in der strengen Auswahlliste, denn dort wird der Inhalt der disjunkten Zahlenmengen festgelegt.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Wertzuweisung  :=

Eine Wertzuweisung beschreibt den Wert eines Zustands, sie sagt, durch welchen Wert der Zustand beschrieben werden kann. Ein Zustand kann seinen Wert ändern, und eine Wertzuweisung, die diesen Zustand beschreibt, ist deshalb eine zeitlich begrenzte Aussage. Sie ist in einem Aktivitätsblock notiert und nur gültig, solange der Aktivitätsblock relevant ist.

Um die Beschreibung zu vereinfachen können unveränderliche Zustände, Konstanten notiert werden. Die Beschreibung einer Konstante erfolgt mit einer Wertzuweisung außerhalb eines Aktivitätsblocks. Damit ist diese Zustandsbeschreibung unbegrenzt gültig, der Zustand ist unveränderlich.

Die Wertzuweisung besteht aus dem zu beschreibenden Zustand, gefolgt vom Wertzuweisungssymbol := und schließlich folgt die Beschreibung des Wertes.

!WnWertDemo  
    .EtText
    .$Pi := "3,14159265358"                   // Beschreibung einer Konstanten
    .+BtZuweisungen
        =>  .EtText := "Hallo"                // Beschreibung eines aktuellen Wertes

Beide Werte in diesem Beispiel sind als formlose Wertbeschreibung notiert. Alternativ könnte dafür wie bei jedem anderen Wert auch eine allgemeine formlose Beschreibung verwendet werden. Allerdings ist die formlose Wertbeschreibung der bevorzugte Weg, da hier sicher gestellt ist, dass ein Wert beschrieben wird, und nicht etwa ein anderer Zustand.

Eine Wertzuweisung bedeutet, dass ein Zustand einen Wert angenommen haben muss zum Zeitpunkt, an dem diese Wertzuweisung relevant wird. Sie bedeutet nicht, dass der Zustand zu diesem Zeitpunkt geändert wird. Für die Wertzuweisung an eine Konstante ist dies offensichtlich, denn es gibt außerhalb eines Aktivitätsblocks keinen "Zeitpunkt", die Aussage über den Zustand ist immer gültig. In einem Aktivitätsblock ist die Wertzuweisung Teil einer Checkliste von Wirkungen. Ebenso wie der Aktivitätsblock selbst ist auch die Wertzuweisung posthum, sie blickt also auf Wirkungen von Vorgängen, die bereits ausgeführt und abgeschlossen wurden.

Steht eine Wertzuweisung für einen bestimmten Zustand in der Aufzählung eines Aktivitätsblocks, so kann in diesem Aktivitätsblock, sowie allen über- und untergeordneten geschachtelten Aktivitätsblöcken nur eine inhaltlich identische Wertzuweisung an diesen Zustand notiert sein, ansonsten wäre dies ein Widerspruch in der Spezifikation. Alle Aspekte in den Aufzählungen von geschachtelten Aktivitätsblöcken gelten gleichzeitig. Auch in Aktionen, die in diesen Aktivitätsblöcken genutzt werden, darf dieser Zustand nicht anders beschrieben sein.

In jedem Schritt einer Sequenz kann ein Zustand durch eine andere Wertzuweisung beschrieben sein, unter der Voraussetzung, dass dieser Zustand nicht bereits in einer Aufzählung in diesem Unterblock oder Aktivitätsblock beschrieben ist. Jeder neue Schritt macht die Aussagen des vorangehenden Schrittes irrelevant, deshalb sind unterschiedliche Wertzuweisungen an denselben Zustand widerspruchsfrei.

Mit einer Wertzuweisung werden nicht nur Änderungen beschrieben, sondern auch gegenüber früher unveränderte Zustände, wenn dies von Bedeutung ist. Dabei kann in geschachtelten Aktivitätsblöcken derselbe Zustand durchaus mehrmals oder unterschiedlich detailliert beschrieben werden. Die Widerspruchsfreiheit dieser Beschreibungen ist ein Weg, die Konsistenz der Tango-Spezifikation zu prüfen.

Die Wertzuweisung verknüpft einen Wert mit einem Zustand zu einem gegebenen Zeitpunkt, oder unbegrenzt falls eine Konstante definiert wurde. Der Wert könnte beschrieben werden mit Hilfe von anderen Zuständen in der Spezifikation, deren aktuelle Werte z.B. als Grundlage zur Berechnung des Wertes dienen. Wenn sich fremde Zustände ändern, die zur Berechnung herangezogen werden, so ist dies ohne Bedeutung, da zum Zeitpunkt der Prüfung der jeweils aktuelle Wert verwendet wird. Vorher und nachher ist die Wertzuweisung irrelevant.

Im Unterschied zur Wertzuweisung verknüpft ein Verweis zwei Zustände, so dass sich der eine Zustand ändert, sobald sich der andere ändert. Ein einfacher Verweis kann auf einen anderen Zustand deuten, dann ist dieser andere Zustand mit einem zusätzlichen Namen adressierbar. Wird der Wert des einen Zustands mit Hilfe des anderen berechnet, so ändern sich beide Zustände zugleich, abhängig von der Berechnungsvorschrift. Ein Zustand, der mit einem Verweis an einen anderen angebunden ist, kann auf Veränderungen des anderen Zustands sofort reagieren und z.B. ein Ereignis auslösen. Dies wäre für einen durch eine Wertzuweisung beschriebenen Zustand nicht möglich, auch dann nicht, wenn der Wert aus anderen Zuständen berechnet wird.

Ein Zustand, der mit einer Wertzuweisung außerhalb eines Aktivitätsblocks beschrieben wird, ist eine Konstante, deshalb muss der Anfangswert eines veränderbaren Zustands in einem Aktivitätsblocks beschrieben werden, wie im folgenden Beispiel Aufrufzähler demonstriert.


Beispiel einer Tango-Spezifikation: Aufrufzähler
!#WnPrompter
    .TxHallo := "Bitte quittieren"
    .TxZähler : _Integer
    .+BtOK
        =>  .WnPrompter.CLOSE
            .TxZähler := "TxZähler + 1"

!+Init
    =>  .$WnPrompter.TxZähler := 0

Der Anzeigetext WnPrompter.TxHallo ist unveränderlich, sein Inhalt wird außerhalb eines Aktivitätsblocks beschrieben. Der Zähler WnPrompter.TxZähler ist veränderlich und wird im Aktivitätsblock zu Init vorbesetzt. Wie dieser Aktivator ausgelöst wird, muss in der Spezifikation nicht beschrieben werden. Der Zähler ist nach dem Auslösen von WnPrompter.BtOK hochgezählt, dies ist aber erst beim nächsten Öffnen von WnPrompter sichtbar, da das Fenster anschließend geschlossen ist.11)

Das Schließen des Fensters WnPrompter hat keine Wirkung auf den Zustand von WnPrompter.TxZähler. Aspekte außerhalb eines Aktivitätsblocks sind immer gültig, das Auslösen eines Ereignisses wie WnPrompter.CLOSE hat deshalb keine Auswirkung auf die Existenz eines solchen Aspekts. Soll ein Ereignis einen Einfluss auf den Wert eines Zustands bekommen, so muss dies explizit beschrieben werden wie im Aktivitätsblock zu WnPrompter.BtOK.

Der Wert eines Zustands kann auf vielfältige Weise beschrieben werden, und damit auch die rechte Seite einer Wertzuweisung. Der Detaillierungsgrad dieser Beschreibung kann der Situation angepasst werden. Die rechte Seite der Wertzuweisung wird immer als Wert interpretiert. Wenn ein Zustand an Stelle des Wertes notiert ist, dann wird der aktuelle Wert des Zustands verwendet. Diese Systematik kann geändert werden durch expliziten Hinweis auf die Interpretation, z.B. können Aspekte selbst als Wert verwendet werden, so dass eine objektorientierte Beschreibung möglich wird. Die nachfolgende Liste enthält einige gängige Möglichkeiten, Werte zu beschreiben:

Die rechte Seite einer Wertzuweisung muss nicht ein Wert oder ein Zustand sein. Es kann jeder Aspekt zur Beschreibung verwendet werden, der einen Zustand als Unteraspekt hält, aus dem sich ein Wert ableiten lässt. Dieser Zugriff auf den Zustand erfolgt explizit durch Angabe eines Pfades, oder implizit durch Zugriff auf das Domänenwissen, aus dem ableitbar ist, welcher Unteraspekt und welcher Wert genutzt werden soll.

Ebenso muss die linke Seite der Wertzuweisung kein Zustand sein, jeder Aspekt mit einem Zustand als Unteraspekt kann Gegenstand einer Wertzuweisung sein. Auch hier ist die explizite Angabe eines Pfades oder die implizite Zuordnung durch Domänenwissen möglich.

!WnWertVarianten  
    .EtText
    .TxText
    .$TextGuiObjekt
    .+BtZuweisungen
        =>  .EtText := "Hallo"                  // Wert ist "Hallo"
            .TxText := EtText                   // Wert ist "Hallo"
            .TextGuiObjekt := EtText.OBJECT     // Wert ist das Element EtText

Die Wertzuweisung an EtText betrifft nicht das Eingabetextfeld selbst, sondern seinen Inhalt, die exakte Formulierung ohne Domänenwissen könnte lauten EtText.INHALT := "Hallo". TxText erhält einen Wert, der mit EtText beschrieben wird, hier greift das Domänenwissen zweimal, einmal wird als bekannt vorausgesetzt, dass TxText.INHALT der betroffene Zustand des Anzeigetextfeldes ist, zum Andern wird EtText.INHALT als zuzuweisender Wert genutzt. Der terminale Aspekt OBJECT liefert das gesamte GUI-Element EtText als Wert für den Zustand $TextGuiObjekt.


		Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
		
 

Senden  <<

In einem Aktivitätsblock kann Information durch Senden an einen Empfänger übermittelt werden. Dabei werden momentan gültige Werte übermittelt, der Empfänger kann die erhaltene Information auswerten, aber nicht die Zustände im Produkt ändern. Wenn der Empfänger die Möglichkeit erhalten soll, Zustände im Produkt zu verändern oder Veränderungen des Zustands zu beobachten, dann wird dies explizit notiert, z.B. indem die Aspekte selbst als Wert übermittelt werden, wie beim Thema Wertzuweisung besprochen. Das Senden kann auf drei verschiedene Arten durchgeführt werden:

Durch Senden wird dem Empfänger Information zur Verfügung gestellt. Es steht dem Empfänger frei, ob und wann er diese Information nutzt, und ob er den Eingang dieser Information überhaupt zur Kenntnis nimmt.12) Die Aufmerksamkeit des Empfängers kann erzwungen werden, wenn ein Aktivator des Empfängers ausgelöst wird und die Information an diesen Aktivator versandt wird.

Versandte Information wird in der EXTERN-Wolke des Empfängers zur Verfügung gestellt. Alternativ kann zur Übertragung der Information ein Kanal des Empfängers verwendet werden. Aus Sicht des Senders ist der Kanal eine mit Namen oder einer allgemeinen formlosen Beschreibung gekennzeichnete Informationssenke beim Empfänger. Für den Sender ist die Nutzung eines Kanals ein alternativer Weg um den Zweck der übertragenen Information zu beschreiben. Der Empfänger hat die Möglichkeit, auf die ankommende Information durch geeignete Aktivatoren sofort zu reagieren. Wenn die Information stattdessen in der EXTERN-Wolke abgelegt ist, dann muss der Empfänger explizit auf diese Information zugreifen und kann nicht automatisch reagieren. Der Sender weiß nicht, ob der Kanal des Empfängers über einen solchen Aktivator verfügt oder nicht.

Nachfolgend werden die Alternativen für das Senden aus der Perspektive des Senders und des Empfängers vorgestellt. Das Senden direkt an den Empfänger führt zu einer Ablage in der EXTERN-Wolke, die nach Belieben vom Empfänger genutzt werden kann:

// SENDER

!#WnSenden
    .+BtSendeJetzt
        =>  .EMPFÄNGER << "Hallo"
// EMPFÄNGER

!#WnEmpfangen
    .TxGruß
    .+BtGrußHolen
        =>  .?{Gruß da} =
                = "Ja, Gruß ist da"
                    =>  .TxGruß := EXTERN.{Gruß}
                = "Nein, kein Gruß"
                    =>  .TxGruß := LEER

Durch das Senden an einen Kanal des Empfängers wird der Zweck der übertragenen Information deutlich gemacht, sowohl beim Sender als auch beim Empfänger:

// SENDER

!#WnSenden
    .+BtSendeJetzt
        =>  .EMPFÄNGER.GRUSS << "Hallo"
// EMPFÄNGER

!$GRUSS                   // das ist der Kanal

!#WnEmpfangen
    .TxGruß
    .+BtGrußHolen
        =>  .?GRUSS =
                = "Kein neuer Gruß da"
                    =>  .TxGruß := LEER
                = "Neuer Gruß da"
                    =>  .TxGruß := $GRUSS.neuerGruß

Der Kanal des Empfängers kann einen Aktivator halten, der die sofortige Weiterverarbeitung der Information anstößt. Für den Sender ist dieser Mechanismus unsichtbar:

// SENDER

!#WnSenden
    .+BtSendeJetzt
        =>  .EMPFÄNGER.GRUSS << "Hallo"
// EMPFÄNGER

!$GRUSS
    .+EvNeuerGruß
        =>  .WnEmpfangen.TxGruß := {dieser Gruß}

!#WnEmpfangen
    .TxGruß

Wenn der Sender Wert darauf legt, dass die Information sofort bearbeitet wird, dann löst er beim Empfänger einen Aktivator aus, indem er ein entsprechendes Ereignis generiert. GRUSS ist jetzt kein Kanal mehr, sondern ein Aktivator:

// SENDER

!#WnSenden
    .+BtSendeJetzt
        =>  .*EMPFÄNGER.GRUSS << "Hallo"
// EMPFÄNGER

!+GRUSS
    =>  WnEmpfangen.TxGruß := EXTERN.{Gruß}

!+WnEmpfangen
    .TxGruß

Der Empfänger ist möglicherweise in der Spezifikation des Produkts nicht explizit beschrieben. Stattdessen wird er über ein Terminal angesprochen, z.B. EMPFÄNGER. Dies bedeutet, dass alle verwendeten Kanäle und Aktivatoren stillschweigend vorausgesetzt werden. Aus Sicht der Tango-Spezifikation ist unerheblich, dass die Aktivatoren oder Kanäle eines fremden Systems möglicherweise andere als die verwendeten Namen tragen könnten. Wichtig ist, dass in der Tango-Spezifikation der Zweck des Sendens klar erkennbar ist. Damit wäre, falls notwendig, ein Abgleich mit einer fremden Spezifikation möglich.

Es gibt keine Vorgabe, was mit der Information in der EXTERN-Wolke oder einem Kanal geschieht, nachdem sie gelesen wurde, auch gibt es keine Vorgaben, ob ältere Information von neuer Information überschrieben wird oder ob eine Warteschlange entsteht. Wenn derartige Details relevant sind, dann wird entweder auf das Domänenwissen zurückgegriffen, oder das Verhalten wird genauer erläutert durch Verfeinerung oder eine geeignete Beschreibung des Aspekts, wie hier beim Empfänger:

// SENDER

!#WnSenden
    .+BtSendeJetzt
        =>  .EMPFÄNGER << "Hallo"
// EMPFÄNGER

!+WnEmpfangen
    .TxGruß
    .+BtPruefeGruß
        =>  .?{neuer Gruß da} =
                = "Ja, mindestens ein neuer Gruß"
                    =>  .TxGruß := EXTERN.{letzter empfangener Gruß}
                = "Nein, nichts Neues"
                    =>  .TxGruß := LEER

Das Produkt kann auch an sich selbst senden. Es können Aktivatoren ausgelöst und Aktionen mit zusätzlicher Information versorgt werden. Alle hier vorgestellten Methoden sind auch beim Senden an das Produkt selbst zulässig. Wenn keine Terminale verwendet werden, dann kann überprüft werden, ob die verwendeten Aktivatoren und Kanäle vorhanden sind.

In Beispiel Kommandofenster wird die Aktion @KommandoAusführen durch Senden mit dem auszuführenden Kommando versorgt. Eine andere Methode zur Parameterübergabe wäre hier ungünstig, da diese Aktion aus zwei Quellen gespeist wird, einmal direkt aus WnEditorFenster.Selektion, und einmal aus der Interpretation der Selektion als KommandoListe.

Senden an eigene Aspekte ist flexibler als Wertzuweisung und Verweis. Trotzdem sollte, wenn möglich auf das Senden an Aktionen und Aktivatoren verzichtet werden. Aktivitätsblöcke sind an bestimmte Rahmenbedingungen gebunden und zu dieser Bindung passen Wertzuweisung und Verweis besser als das Senden. Aktionen sind zwar aus dem Kontext herausgelöste Aktivitätsblöcke, aber sie sollten nur so weit wie unbedingt nötig herausgelöst werden. Je flexibler ein Aktivitätsblock verwendet wird, desto abstrakter muss er beschrieben werden. Die konkrete Beschreibung ist das Ziel einer Tango-Spezifikation. Flexibilität von Prozeduren und Funktionen ist ein Zeichen guter Implementierung, aber Aktivitätsblöcke und Aktionen sind keine Prozeduren oder Funktionen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Verzweigung  ? =  =

Eine Verzweigung erlaubt, die Relevanz von Aktivitätsblöcken abhängig zu machen vom momentanen Wert eines Wertlieferanten. Als Wertlieferant kann ein Zustand dienen, aber auch Aktionen, das Senden-Konstrukt oder ein ausgelöster Aktivator. Der Wertlieferant kann formlos beschrieben sein, und er muss sich nicht auf andere, bereits vorhandene Aspekte der Spezifikation beziehen. Alle möglichen Werte des Wertlieferanten müssen in der Verzweigung berücksichtigt werden, andernfalls wäre die Spezifikation fehlerhaft.

!@DruckeErgebnis
    =>  .? $gefahreneJahresKm =
            = NULL
                =>  .@DruckeMeldung << "Keine Fahrleistung notiert"
            = "< 20 000 km"
                =>  .@DruckeWenigfahrerQuittung
            = ">= 20 000 km"
                =>  .@DruckeVielfahrerQuittung

Nach dem einleitenden Fragezeichen ? folgt der Wertlieferant, gefolgt von einem Gleichheitszeichen =. Jede Prüfalternative, also die Beschreibung eines möglichen Wertes oder einer Menge von Werten, wird auf einer eigenen Zeile eingerückt und mit = eingeleitet. In der nächsten Zeile beginnt ein Aktivitätsblock, der ausgewertet wird, wenn die Prüfalternative zutrifft. Jede nachfolgende Prüfalternative setzt implizit voraus, dass alle vorangehenden Prüfalternativen nicht zutreffen, die Reihenfolge ist signifikant. In jeder möglichen Situation wird genau eine Prüfalternative gültig, und damit wird genau ein Aktivitätsblock relevant.

Im folgenden Beispiel wird die Prüfalternative 2 niemals aktuell, da bereits vorher die Prüfalternative geradeZahl zutrifft.

!$eineZahl : ( "0..", _Integer )

!+zahlSetzen
    =>  .eineZahl := ( _Zufallszahl, _Integer )

!+zahlPrüfen
    =>  .? eineZahl =
            = 0
                =>  USER << "0"
            = geradeZahl
                =>  USER << "gerade Zahl"
            = 2
                =>  USER << "NIEMALS"         // kann niemals zutreffen
            = ungeradeZahl
                =>  USER << "ungerade Zahl"

Das einleitende Gleichheitszeichen jeder Prüfalternative bedeutet nicht automatisch eine Prüfung auf Gleichheit. Jede beliebige Vergleichsoperation kann verwendet werden, und sie wird in der Prüfalternative selbst notiert. Ebenso wäre möglich, dass der Wertlieferant überhaupt nicht zur Prüfung verwendet wird. Einzige Bedingung bei der Formulierung der Prüfalternative ist, dass sie zu einem klaren Ergebnis ausgewertet werden kann.

Das nachfolgende Beispiel Ampel entscheidet, ob ein Auto weiterfahren darf oder nicht. Dazu werden Ampel, Verkehrsschild und Verkehrslage berücksichtigt. Der einleitende Wertlieferant {Kreuzung mit Ampel, Schild oder RechtsVorLinks} beschreibt nur die Situation, er wird aber zum eigentlichen Vergleich nicht verwendet, da die Prüfalternativen zu unterschiedlich sind.


Beispiel einer Tango-Spezifikation: Ampel
!+FreieFahrtPrüfen
    =>  ? {Kreuzung mit Ampel, Schild oder RechtsVorLinks} =
            = Ampel.[ ROT | ROTGELB | GELB ]
                =>  .FAHRER << "Nicht weiterfahren"
            = Ampel.GRÜN
                =>  .FAHRER << "Weiterfahren"
            = [ Ampel.BLINKTGELB | Verkehrsschild.VORFAHRTBEACHTEN ]
                =>  .? {Querstraße frei} =
                        = "Ja, frei"
                            =>  .FAHRER << "Weiterfahren"
                        = "Nein, kommt was"
                            =>  .FAHRER << "Nicht weiterfahren"
            = Verkehrsschild.VORFAHRTSTRASSE
                =>  .FAHRER << "Weiterfahren"
            = "Kein vorfahrtsregelndes Schild"
                =>  .? {Rechts frei} =
                        = "Ja, frei"
                            =>  .FAHRER << "Weiterfahren"
                        = "Nein, nicht frei"
                            =>  .FAHRER << "Nicht weiterfahren"

Mehrere Alternativen führen in diesem Beispiel zum selben Aktivitätsblock. Dies lässt sich durch eine Auswahlliste beschreiben, entweder als Wertemenge des Aspekts wie bei Ampel.[ ROT | ROTGELB | GELB ], oder als Prüfalternative wie bei [ Ampel.BLINKTGELB | Verkehrsschild.VORFAHRTBEACHTEN ].

Eine Verzweigung in der Aufzählung eines Aktivitätsblocks führt in einen geschachtelten Aktivitätsblock, der zusätzliche Wirkungen beschreibt. Die Checkliste von Wirkungen des äußeren Aktivitätsblocks wird um weitere Wirkungen ergänzt. Es gibt, anders als bei Funktionsaufrufen in Programmiersprachen, keine "Rückkehr" aus dem geschachtelten Aktivitätsblock, da nur eine einzige, verlängerte Checkliste abzuarbeiten ist und alle Wirkungen aller geschachtelten Aktivitätsblöcke gleichzeitig geprüft werden.

Eine Verzweigung in einem Schritt der Sequenz eines Aktivitätsblocks ergänzt die Checkliste dieses einen Schritts. Nachdem die Wirkungen dieses Schritts und seiner geschachtelten Aktivitätsblöcke eingetreten sind, wird mit dem nächsten Schritt der Sequenz fortgefahren.

Im nachfolgenden Beispiel Videorekorder muss unter bestimmten Umständen die Cassette gewechselt oder zurückgespult werden. Danach wird die Aufnahme programmiert.


Beispiel einer Tango-Spezifikation: Videorekorder
!+AufnahmeProgrammieren
    =>  -?{Eingelegte Cassette} = 
            = "Keine Cassette eingelegt"
                =>  .{Cassette mit genug Platz einlegen}
            = "Nicht genug Restzeit"
                =>  .?{Inhalt wichtig} =
                        = "Nein, unwichtig"
                            =>  .{Cassette zurückspulen}
                        = "Ja, wichtig"
                            =>  .{Cassette mit genug Platz einlegen} 
            = "Genug Restzeit"  
                =>  .NOP
        -{Aufnahme programmieren}
        -{Timer aktivieren}

Die allgemeinen formlosen Beschreibungen in diesem Beispiel sind als Handlungen formuliert, tatsächlich wird wie bereits erläutert eine Checkliste von Wirkungen erstellt. Bei jedem der drei Schritte der Sequenz wird eine eigene Checkliste erstellt, diese Listen sind voneinander unabhängig..

Eine Verzweigung in einem Unteraspektblock außerhalb eines Aktivitätsblocks wird ständig geprüft, sie ist nicht von einem bestimmten Gesamtzustand abhängig wie ein Aktivitätsblock. Diese Verzweigung beschreibt eine automatische Reaktion auf einen Zustand, der sich ändern kann. Im nachfolgenden Beispiel Läutende Uhr wird in drei Varianten zur vollen Stunde geläutet.


Beispiel einer Tango-Spezifikation: Läutende Uhr
!#WnUhr1
    .TxUhrzeit
        .{wird ständig aktualisiert}
        .?TxUhrzeit =
            = {neue Stunde beginnt}
                =>  .*DINGDONG
            = {Stunde unverändert}
                =>  NOP

!#WnUhr2
    .TxUhrzeit
        .{wird ständig aktualisiert}
        .+CHANGED
            =>  ? {neue Uhrzeit}
                    = {neue Stunde beginnt}
                        =>  .*DINGDONG
                    = {Stunde unverändert}
                        =>  NOP

!#WnUhr3
    .TxUhrzeit
        .{wird ständig aktualisiert}
        .+CHANGED
            =>  & {neue Stunde beginnt}
                    =>  .*DINGDONG

Das Läuten der Uhr wird in WnUhr1 mit einer Eigenschaft beschrieben, die als Verzweigung außerhalb eines Aktivitätsblocks notiert ist. Diese Eigenschaft ist immer gültig, so dass auf die volle Stunde ständig geprüft wird. In WnUhr2 und WnUhr3 wird der Aktivator TxUhrzeit.CHANGED verwendet, um die Prüfung auf die volle Stunde explizit anzustoßen. Die Wirkung ist in allen Fällen dieselbe. Der NOP-Aktivitätsblock kann vermieden werden, wenn wie in WnUhr3 eine Bedingung zur Formulierung verwendet wird. Bedingungen verlangen im Gegensatz zur Verzweigung nicht, dass alle möglichen Werte eines Wertlieferanten behandelt werden.

Ein Vorgang in der realen Welt kann Zeit konsumieren. Wenn Aspekte solche Vorgänge beschreiben, dann ist möglicherweise die Reihenfolge relevant, in der die Ergebnisse der Vorgänge sichtbar werden. Mit einer Sequenz wird eine unbedingte Abfolge von Ergebnissen aus solchen Vorgängen beschrieben.

Wenn Zeit konsumierende Vorgänge von Ergebnissen eines anderen Vorgangs abhängen, dann lässt sich die Synchronisierung mit einer Verzweigung in Kombination mit einem Rückgabewert beschreiben. Die Synchronisierung ergibt sich, wenn ein Zeit konsumierender Vorgang eine Verzweigung enthält, deren Wertlieferant selbst auch ein Zeit konsumierender Vorgang ist. In diesem Fall muss der Vorgang im Wertlieferanten zuerst abgeschlossen sein, bevor der umfassende Vorgang fortgesetzt wird, da der umfassende Vorgang auf das Ergebnis wartet.

Die Bearbeitung eines Vorgangs im Wertlieferanten wird immer abgewartet, selbst wenn der Wertlieferant in den Prüfalternativen der Verzweigung nicht verwendet wird. Zeit konsumierende Vorgänge in den Prüfalternativen sind nicht verboten, sie sollten aber vermieden werden, da nachfolgende Prüfalternativen möglicherweise nicht mehr geprüft werden. Dies bedeutet, dass einige Zeit konsumierende Vorgänge nicht ausgeführt werden, und damit werden starke Implementierungsvorgaben gemacht, die von der Lesart des Verzweigungs-Konstrukts und damit letztlich von Details der Beschreibungsmethodik abhängen. Diese Vorgehensweise grenzt an "Trickprogrammierung" und ist nicht im Sinne der Tango-Beschreibungsmethodik.

Wenn in einem Wertlieferanten kein Zeit konsumierender Vorgang vorkommt, sondern nur die Prüfung auf Zustände wie im Beispiel Läutende Uhr, dann muss zwar auch der Rückgabewert vorliegen, bevor in der Verzweigung über das weitere Vorgehen entschieden wird, aber dies alles geschieht gleichzeitig, so dass schlussendlich eine einzige große Checkliste bearbeitet werden kann, die den Zustand zu diesem Zeitpunkt beschreibt.

Im Beispiel Telefonieren-Protokoll ist Telefon.NummerWählen ein Zeit konsumierender Vorgang. Der Vorgang ist Wertlieferant in einer Verzweigung von +IchRufeAn. Erst wenn das Ergebnis von Telefon.NummerWählen vorliegt, kann entschieden werden, dass z.B. der Fall "Besetzt-Signal" vorliegt, so dass Telefon.HörerAuflegen der nächste Zeit konsumierende Vorgang ist. Die Beschreibung stellt die Reihenfolge dieser beiden Vorgänge sicher.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Bedingung  &

Eine Bedingung ist ein Aspekt, der eine logische Aussage repräsentiert. Sie wird mit einem & eingeleitet. Ein Aktivitätsblock unter dieser Bedingung ist relevant, wenn die Bedingung zutrifft. Alle Bedingungen einer Aufzählung in einem Aktivitätsblock oder Unteraspektblock sind voneinander unabhängig, jede hat ihren eigenen Aktivitätsblock und es können eine, keine oder mehrere Bedingungen gleichzeitig zutreffen.

!+Bekleidungsfrage
    =>  &Wetter.SAUKALT
            => .{Handschuhe dabei}
        &Straße.GLATT
            => .{Stiefel mit Profil verwenden}

Aufzählungspunkte vor Bedingungen werden normalerweise weggelassen zur Vermeidung einer syntaktischen Falle.13)

Bedingungen prüfen Wertlieferanten auf einzelne Werte oder Wertemengen, es wird nicht verlangt, dass alle möglichen Werte behandelt werden müssen, die der Wertlieferant annehmen kann.

Eine Bedingung ohne Aktivitätsblock kann mit einer weiteren Bedingung UND-verknüpft sein, dazu wird die erste Bedingung mit einem & abgeschlossen und die nächste Bedingung im Unteraspektblock hinzugefügt. In diesem Unteraspektblock kann eine Aufzählung von Bedingungen stehen, die dann alle mit der übergeordneten Bedingung UND-verknüpft, aber voneinander unabhängig sind. Die geschachtelten Bedingungen, die auf oberster Ebene zu einer einzelnen Aufzählung gehören, werden als Bedingungskaskade bezeichnet.

Wird eine Bedingung ohne Aktivitätsblock mit einer weiteren Bedingung UND-verknüpft, so kann auf den zusätzlichen Unteraspektblock verzichtet werden, stattdessen wird die zusätzliche Bedingung mit && hinter die erste Bedingung geschrieben.

!+RolloBedienen
    =>  & {Sonne scheint} &
            & {Südseite} 
                =>  .{Rollo heruntergefahren}
            & {Westseite} && {Nachmittag}
                =>  .{Rollo heruntergefahren}
        & [ {Nachtarbeit} | {Beamer-Vortrag} ]
            =>  .{Rollo heruntergefahren}

Wenn die {Sonne scheint} sind noch zusätzliche Bedingungen zu prüfen, die UND-verknüpft im Unteraspektblock niedergeschrieben sind. Die Bedingungen {Westseite} und {Nachmittag}. sind nur gemeinsam relevant, deshalb werden sie auf eine Zeile zusammengezogen. Alternativ könnte {Nachmittag} auch als UND-verknüpfter Unteraspekt von {Westseite} notiert sein.

Die Alternativen {Nachtarbeit} und {Beamer-Vortrag} sind ODER-verknüpft und führen in denselben Aktivitätsblock. ODER-Verknüpfungen werden als Bedingung mit einer Auswahlliste formuliert.

Im Beispiel oben wird nur auf Bedingungen geprüft, in denen das {Rollo heruntergefahren} ist. Eine zusätzliche Bedingung in diesem Beispiel wäre problematisch:

        & {Bewölkt}
            =>  .{Rollo ist oben} 

Im Falle eines Beamer-Vortrags bei bewölktem Himmel werden zwei Bedingungen gültig, deren Aktivitätsblöcke einander widersprechen. Dieser Fehler kann nur aus dem Domänenwissen erkannt werden, denn nur daraus lässt sich ableiten, dass beide Bedingungen gleichzeitig eintreten können. Eine formale Prüfung der Tango-Spezifikation auf Konsistenz könnte dieses Problem nicht erkennen. Bedingungen sind ein mächtiges Konstrukt, das mit großer Sorgfalt eingesetzt werden muss. Eine Verzweigung ist besser prüfbar und in der Formulierung einer Aussage resistenter gegen derartige Fehler.

Alle Bedingungen einer Bedingungskaskade werden gleichzeitig, "auf einen Schlag" geprüft, es gibt keine implizite Sequentialisierung der Prüfungen. Deshalb ist die Bedingung nicht besonders geeignet, um Ergebnisse aus Zeit konsumierenden Vorgängen zu prüfen. Wertlieferanten, die Zeit konsumieren, sind nicht verboten, können aber zu schwer interpretierbaren Beschreibungen führen, insbesondere wenn mehrere dieser Wertlieferanten in einer Bedingungskaskade verwendet werden.

Eine Bedingung kann wie jeder Aspekt durch Unteraspekte näher erläutert werden:

        ...
        & KochzeitBeendet
            .[ {Wecker hat geklingelt} | {Nudeln sind schon weich} ]
            =>  .{Topf von der Platte nehmen}
                .{Platte ausschalten} 

Trifft eine Bedingung in der Aufzählung eines Aktivitätsblocks zu, so erweitert sie die Checkliste dieses Aktivitätsblocks um ihren eigenen Aktivitätsblock.In der Sequenz eines Aktivitätsblocks erweitert sie die Checkliste eines einzelnen Schritts.

In einem Unteraspektblock außerhalb eines Aktivitätsblocks beschreibt die Bedingung eine Eigenschaft. Die Relevanz eines Aktivitätsblocks wird fest mit einem Zustand verknüpft und ständig aktualisiert:

!#WnBuchhaltung
    .TxSaldo
        .Textfarbe
        & TxSaldo.">= 0"
            =>  .Textfarbe := SCHWARZ
        & TxSaldo."< 0" 
            =>  .Textfarbe := ROT

Abschließende Anmerkung zur Nutzung von Verzweigung und Bedingung

Mit Verzweigung und Bedingung lassen sich logische Funktionen in Tango darstellen. Die Verzweigung arbeitet die einzelnen Prüfalternativen sequentiell ab, damit werden frühere Prüfalternativen implizit negiert, was die Formulierung von nachfolgenden Prüfalternativen erleichtert.

Die Bedingung ist geeignet, um logische Funktionen in Tango zu beschreiben, die mit dem Karnaugh-Diagramm (auch Karnaugh-Veitch-Diagramm) optimiert wurden. Die disjunktive Normalform der damit ermittelten minimalen Funktion lässt sich effizient durch eine Bedingungskaskade beschreiben, denn in dieser Funktion sind UND-verknüpfte Terme mit ODER aneinander gereiht.

Bedingungen und Verzweigungen können nur die Relevanz von Aktivitätsblöcken beeinflussen, sie sind nicht geeignet, um damit die Existenz oder Nichtexistenz von statischen Aspekten zu beschreiben. Eigenschaften sind immer gültig, Elemente wie z.B. Knöpfe oder Felder sind immer vorhanden, sie könnten aber unter bestimmten Bedingungen unsichtbar oder unbenutzbar sein, und diese Eigenschaften lassen sich in Aktivitätsblöcken ändern.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

5.5 Weitere strukturierende Sprachelemente

Einem Dokument mit einer Tango-Spezifikation können Hinweise als Kommentare hinzu gefügt werden, die nicht als Teil der Beschreibung des Produkts betrachtet werden. Kommentare liefern keine zusätzliche Information zur Tango-Spezifikation. Die Spezifikation kann mit speziellen Kommentaren in Bereiche geteilt werden, um die Lesbarkeit zu verbessern oder zur Vorbereitung der späteren Weiterverarbeitung.

Leerzeilen werden zur optische Strukturierung einer Spezifikation eingefügt und sind ansonsten völlig bedeutungslos. Zur eindeutigen Abgrenzung von Namen und Sprachelementen der Tango-Beschreibungssprache werden Leerzeichen verwendet, da fast alle anderen Sonderzeichen in Namen vorkommen können und somit nicht als Begrenzung signifikant sind.

Das Einrücken von Zeilen ist in der Tango-Spezifikation von größter Bedeutung, denn dadurch wird die Teile-Beziehung dargestellt. Dies gilt jedoch nicht für Folgezeilen, die durch einen willkürlichen Zeilenumbruch entstehen.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Kommentar //

Ein Kommentar ist kein Teil der Beschreibung des Produkts, er liefert außerhalb der Spezifikation zusätzliche Information für den Leser. Er wird durch doppelte Schrägstriche // an einer beliebigen Stelle einer Zeile eingeleitet und reicht bis zum Ende der Zeile.

Innerhalb von allgemeinen formlosen Beschreibungen und formlosen Wertbeschreibungen sind Kommentare nicht möglich, d.h. doppelte Schrägstriche darin werden nicht als Kommentarsymbol erkannt.

                                // dies ist ein Kommentar in einer eigenen Zeile
!EinElement                     // EinElement ist noch nicht beschrieben
    ...                         // hier fehlt noch was
Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Bereich

Siehe auch: Konzepte

Eine Tango-Spezifikation kann in Bereiche gegliedert sein, um die Lesbarkeit zu verbessern, oder um solche Definitionen zusammenzufassen, die in späteren Projektschritten in gleicher Weise weiterverarbeitet werden sollen. Die Gliederung in Bereiche hat keinerlei Auswirkungen auf den Inhalt der Spezifikation. Ein Definitionsblock sollte nicht in verschiedene Bereiche aufgeteilt sein.

Ein Bereich wird durch drei Kommentarzeilen eingeleitet, die Bezeichnung des Bereichs steht in der zweiten Zeile, in Großbuchstaben und gesperrt. Ein Bereich endet dort, wo der nächste beginnt oder am Ende der Datei, Bereiche werden nicht geschachtelt.

//
// A L I A S
//

   // dies ist der Bereich ALIAS

Je nach angestrebtem Zweck können Bereiche beliebig definiert werden. Eine umfangreichere Zusammenstellung von Bereichen aus mehreren Software-Projekten findet sich im Anhang. Die Definition von Bereichen ist bei der Erstellung der Spezifikation nützlich als Gedankenstütze und zur Entscheidung, was in die Spezifikation aufgenommen werden soll.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Leerzeile

Leerzeilen sind nicht signifikant. Sie werden ausschließlich zur besseren Lesbarkeit eingefügt. Es ist üblich, dass nach einem Definitionsblock mindestens eine Leerzeile eingefügt wird.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Leerzeichen

Siehe auch: Sprachelemente

Leerzeichen am Anfang der Zeile bilden die Einrückung und sind deshalb signifikant. Sie werden im nächsten Abschnitt besprochen.

Als Leerzeichen gelten die Zeichen Space, Tabulator, und das Zeilenende. Mehrere aufeinanderfolgende Zeichen der genannten Art wirken wie ein einzelnes Leerzeichen, abgesehen von der bereits erwähnten Einrückung. Betriebssysteme können weitere Zeichen als Leerzeichen hinzufügen. In jedem Fall werden die ASCII-Zeichen CR und LF allein und in Kombination als Zeilenende erkannt.

Vor und nach Namen sollten Leerzeichen eingefügt werden. In Namen können fast alle Zeichen vorkommen, aber keine Leerzeichen, deshalb werden Namen durch Leerzeichen eindeutig begrenzt. Vor Namen werden Symbole der Tango-Beschreibungssprache als Sprachelemente interpretiert, und der Name beginnt beim ersten Zeichen, das kein Sprachelement ist. Der Namensanfang ist damit meist eindeutig und Leerzeichen zwischen Sprachelementen und Namen können normalerweise entfallen. Für das Namensende gibt es kein ähnlich starkes Kriterium, deshalb sind Leerzeichen nach dem Namen der einzige Weg, das Namensende sicher zu markieren, wenn in der Zeile nach dem Namen weiterer Text folgt.

Zwischen Sprachelementen der Tango-Beschreibungssprache können optional Leerzeichen gesetzt werden. Sprachelemente aus mehreren Sonderzeichen dürfen nicht durch Leerzeichen getrennt werden, so z.B. der Wirkungspfeil =>. In einem Pfad sind Leerzeichen nicht möglich, außer eingeschlossen in Klammern oder Gänsefüßchen in formlosen Beschreibungen und Auswahllisten.

Es folgen einige Beispiele für korrekte und nicht korrekt gesetzte Leerzeichen:

!#WnMeinFenster1                // übliche Schreibweise, OK
    ...

    !#WnMeinFenster2            // führende Leerzeichen bei Definitionsblöcken ohne Bedeutung, aber OK
        .EtEinFeld              // führende Leerzeichen als Einrückung der Teile-Beziehung wichtig
 
! # WnMeinFenster3                   // mit Leerzeichen zwischen den Markierungen OK 
    . + BtMeinKnopf
        =>.{tu was}                  // nach dem Wirkungspfeil ist ein Leerzeichen unnötig, OK
          . ? {Fenster sichtbar}=    // Leerzeichen nach formloser Beschreibung überflüssig, OK 
              ="Ja, sichtbar"        // Leerzeichen nach = überflüssig, OK
                  =>...              // alles Tango-Sprachelemente, OK
    .$Ref <-$WnMeins.{das da}.links  // OK
             

!#WnFehlerfenster//                FALSCH, Kommentarzeichen sind Teil des Namens 
    . # Unteres Fenster         // FALSCH, Leerzeichen im Namen nicht erlaubt
        . . .                   // FAlSCH, Ellipse darf keine Leerzeichen enthalten
    .$Wkn <- WnAktien . Wkn     // FALSCH, Pfad darf kein Leerzeichen enthalten
    .$ Depot<- WnAktien.Anzahl  // FALSCH, Name und Verweis-Symbol nicht mit Leerzeichen getrennt
    .?AllesFertig=              // FALSCH, = ist Namensteil
        ="Ja, fertig" 
            = >  .{tu was}      // FALSCH, Wirkungspfeil enthält Leerzeichen
        ="Nein, noch nicht   " 
        => .{weiter warten}     // FALSCH, Einrückung fehlt 

Diese Regeln lassen sich am Einfachsten einhalten, wenn grundsätzlich Leerzeichen gesetzt werden rund um Namen und Tango-Sprachelemente außer bei Markierungen (dort optional) und in Pfaden.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Einrücken

Siehe auch: Sprachelemente

Das Einrücken von Zeilen bezeichnet in einer Tango-Spezifikation eine Teile-Beziehung und ist deshalb signifikant. Daneben gibt es Einrückungen, die der besseren Lesbarkeit dienen.

Wenn die Spezifikation in einer Textdatei abgelegt ist, so ist darauf zu achten, dass nicht durch eine Mischung aus Tabulatoren und Leerzeichen das Einrücken von Zeilen verändert wird, wenn die Datei mit einem anderen Editor betrachtet wird. Es wird dringend empfohlen, bei der Ablage von Spezifikationen in Textdateien entweder nur Tabulatoren oder nur Leerzeichen zu verwenden. Bei der Anzeige sollte ein Zeichensatz mit einheitlicher Zeichenbreite verwendet werden.

In der Niederschrift einer Teile-Beziehung sind die Zeilen des Unterblocks gegenüber dem übergeordneten Aspekt gleich weit eingerückt. Auf diese Weise wird der Zusammenhang zwischen Unterblock und übergeordnetem Aspekt dargestellt. Dabei ist unerheblich, um welche Strecke (z.B. die Anzahl der Leerzeichen) eingerückt wird. Üblich ist ein Einrücken um vier Space-Zeichen oder ein Tab-Zeichen

Ein Aktivitätsblock ist gegenüber dem übergeordneten Aspekt um insgesamt zwei Stufen eingerückt. Der Aktivitätsblock ist selbst der Aspekt eines Unteraspektblocks und wird in diesem repräsentiert durch den Wirkungspfeil, der wie alle anderen Aspekte dieses Blocks um eine Stufe eingerückt ist. Der Inhalt des Aktivitätsblocks ist ein Unterblock des Wirkungspfeils und deshalb nochmals um eine Stufe eingerückt.14) Um die übliche Schreibweise von Unterblöcken einzuhalten könnte der Wirkungspfeil alleine auf einer Zeile stehen, in der nächsten Zeile folgt dann der eingerückte Block mit dem Inhalt des Aktivitätsblocks. Diese Notation ist erlaubt, aber unüblich.

!+BtKlickMich
    =>  .meineAktion1
        .undNochEineAktion

!+BtKlickMichUnüblich
    =>                        // Beginn des Aktivitätsblocks
        .meineAktion1         // und das ist die Beschreibung dynamischer Aspekte
        .undNochEineAktion

In Tango-Spezifikationen wird der Inhalt von Klammern üblicherweise nicht weiter links notiert als die öffnende Klammer selbst. Die schließende Klammer muss nicht hinter der letzten Inhaltsspalte stehen. Diese Einrückungskonvention für Klammerinhalte dient der Lesbarkeit, sie verändert die Bedeutung nicht. Die Konvention ist auch für Gänsefüßchen üblich, wenn sich eine formlose Wertbeschreibung über mehr als eine Zeile erstreckt.

    .EtDateiMitPfad : [ leer | FormatFalsch | VerzeichnisExistiertNicht |
                        DateiExistiert | DateiIstNeu ]

Eine Folgezeile entsteht durch einen willkürlichen Zeilenumbruch, der aus einer Zeile zwei Zeilen macht wie in diesem Klammerbeispiel. Der Zeilenumbruch gilt als Leerzeichen. Eine Folgezeile ist üblicherweise deutlich stärker eingerückt als die erste Zeile, mindestens um zwei Stufen. Diese Einrückung ist optional, die Bedeutung ändert sich durch die Einrückung nicht. In Klammerausdrücken ist die Einrückung hinter die öffnende Klammer gewöhnlich die dominante Regel.

Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor
 

Zeilenumbruch

Siehe auch: Sprachelemente

Ein Konstrukt der Tango-Beschreibungssprache kann nach Belieben auf mehrere Zeilen aufgeteilt werden. Wenn das Konstrukt in einer Zeile erkennbar unvollständig ist, so werden nachfolgende Zeilen als Folgezeilen betrachtet, die das Konstrukt komplettieren. Dies ist der Fall bei Klammerausdrücken, wenn die schließende Klammer in einer Zeile fehlt, ebenso bei Gänsefüßchen und bei binären Konstrukten, wenn z.B. nach einem Wertzuweisungssymbol := keine rechte Seite folgt. Die Einrückung der Folgezeile ist für die Bedeutung irrelevant. Wenn durch die Trennung die Beschreibung mehrdeutig wird, dann ist die Spezifikation fehlerhaft.

Kommentare können nicht auf mehrere Zeilen verteilt werden, in jeder Zeile muss der Kommentar erneut mit // markiert werden.

Ein Backslash als letztes Zeichen einer Zeile (also die Abfolge Leerzeichen -- Backslash -- EOL, die sicherstellt, dass der Backslash nicht Teil eines Namens ist) erzwingt die Zusammenfassung dieser Zeile mit der nachfolgenden Zeile. In diesem Fall können keine Mehrdeutigkeiten durch die Aufteilung auf mehrere Zeilen entstehen. Das Einrücken der Folgezeile ist für die Bedeutung irrelevant.

.EtDateiMitPfad      \
        : [ leer | FormatFalsch | VerzeichnisExistiertNicht | DateiExistiert | DateiIstNeu ]

Die Komplettierung von syntaktisch unvollständigen Zeilen kann auch erfolgen, indem vorangehende Zeilen zur Komplettierung herangezogen werden. Dies wäre z.B. der Fall, wenn der abschließende Backslash im letzten Beispiel fehlen würde:

.EtDateiMitPfad  
        : [ leer | FormatFalsch | VerzeichnisExistiertNicht | DateiExistiert | DateiIstNeu ]

In diesem Fall ist die erste Zeile komplett, aber die zweite Zeile enthält ein binäres Konstrukt ohne linke Seite, das erst zusammen mit der ersten Zeile Sinn ergibt. Diese Schreibweise ist möglich, kann aber zu Irritationen beim Lesen und maschinellen Auswerten der Spezifikation führen, sie wird deshalb nicht empfohlen.


Kapitel zurückUnterkapitel zurückThema zurückListe aller SprachelementeThema vorUnterkapitel vorKapitel vor