6 Datentypen

In der Regelsprache sind wie in anderen Programmiersprachen auch verschiedene Datentypen definiert, die hier erklärt werden sollen.

Datentyp

Bedeutung

anyvalue

Dieser Datentyp stellt einen beliebigen Datentyp dar. Erst durch die aktuelle Belegung erhält er seinen eigentlich Datentyp. In einem so definierten Wert kann also alles abgespeichert werden, bei der Abfrage ist dann entscheidend, welche Art von Wert zuletzt abgespeichert worden ist.

attribute

Dieser Datentyp ist ein Attribut des Dialog Managers. Er kann daher mit allen vom Dialog Manager definierten Attributen wie .visible oder einem benutzerdefinierten Attribut belegt werden.

boolean

Dieser Datentyp stellt einen booleschen Wert dar. Seine Werte sind entweder true oder false.

class

Dieser Datentyp gibt die Klasse eines Objekts oder einer Ressource an. Werte umfassen z.B. Klassen wie z.B. pushbutton, color, function, ...

datatype

Dieser Datentyp stellt einen Datentyp dar. In ihm können also Werte wie string, object, integer, ... hinterlegt werden.

enum

Dieser Datentyp ist ein Aufzählungstyp. In ihm werden vom Dialog Manager definierte Werte hinterlegt. Dieser Aufzählungstyp kommt z.B. bei der Messagebox zum Einsatz, wenn der Benutzer einen von den angebotenen Pushbuttons drückt.

event

Dieser Datentyp stellt ein Ereignis im Dialog Manager. In ihm können also Werte wie select, dbselect, key und help abgespeichert werden.

index

Dieser Datentyp dient der Adressierung von zweidimensionalen Attributen wie z.B. dem Inhalt eines Tablefields. In diesem Datentyp können zwei ganze Zahlen abgespeichert werden, die zusammen eine Zeile und eine Spalte, also genau eine Zelle adressieren.

integer

Dieser Datentyp stellt eine ganze Zahl dar. Der Wertebereich für diese Zahl ist dabei von -2 31 bis 2 31.

method

Dieser Datentyp stellt eine Methode im Dialog Manager dar. Er kann zum Beispiel die Werte :insert, :delete, :clear oder :exchange annehmen.

object

Dieser Datentyp stellt ein Objekt im Sinn des Dialog Managers dar. Im Sinn des Dialog Managers ist alles ein Objekt, was einen Namen hat oder einen Namen bekommen kann. Damit sind alle Objekte, Ressourcen, Funktionen, Variablen und Regeln Objekte in diesem Sinn.

pointer

Dieser Datentyp stellt einen für die Regelsprache unbekannten Typ dar. Er kann genutzt werden, um anwendungsspezifische Daten im Dialog zu speichern, ohne dass der Dialog den Inhalt dieser Daten kennen muss.

string

Dieser Datentyp stellt eine beliebig lange Zeichenkette im Dialog Manager dar. Die Länge wird dabei automatisch bei einer Zuweisung auf diesen Typ angepasst, so dass hier keine Maßnahmen durch die Anwendung erfolgen müssen.

6.1 Datentypen für Sammlungen

Folgende Sammlungsdatentypen sind im IDM erlaubt. Dabei ist zu beachten, dass für die Adressierung wie auch die adressierten Einzelwerte die Beschränkung gilt, dass nur skalare Typen erlaubt sind. Ein Aufbau von mehrdimensionalen Listen ist also nicht erlaubt.

Tabelle 20-1: Datentypen für Sammlungen (collections)

Datentyp

Bedeutung

list

Dieser Datentyp definiert eine Liste mit beliebigen Werten die im Adressierungsbereich von 0 … 231 liegen. Dabei wird über 0 der Standardwert adressiert, der an alle Listenwerte vererbt wird. Dieser Datentyp ist für die Manipulation von Listen in der Regelsprache vorgesehen und optimiert.

vector

Dieser Datentyp definiert eine Liste, die Werte des gleichen Typs beinhaltet. Einen Standardwert gibt es nicht. Der Adressierungsbereich ist somit von 1 … 231. Dieser Datentyp ist speziell für die Kommunikation mit Objekt-Attributen vorgesehen und nicht für eine schnelle Manipulation optimiert.

refvec

Dieser Datentyp definiert eine Liste, die nur Werte des Typs object beinhaltet. Der Adressierungsbereich geht von 1 … 231 und bietet keinen Standardwert. Jede object-ID wird nur ein einziges Mal aufgenommen, ein null wird nicht in die Liste aufgenommen.

matrix

Dieser Datentyp definiert ein zweidimensionales Feld dessen Werte mit dem index-Datentyp adressiert werden können. Ist die angegebene Zeile (first-Wert des Index) oder die Spalte (second-Wert des Index) 0, so handelt es sich um einen Standardwert der in der Adressierungsreihenfolge [0,0] → [Zeile,0] → [0,Spalte] → [Zeile,Spalte] weitervererbt wird

hash

Dieser Datentyp definiert ein assoziatives Feld mit beliebigem skalaren Adressierungsbereich und beliebigen Werten und einem optionalen Standardwert der zurückgegeben wird für einen Zugriff bei dem der Schlüssel nicht enthalten ist.

Analog zu vordefinierten Vektor- und Matrixattributen wie .content[], .userdata[] usw. ist eine Erweiterung von Sammlungen direkt hinter ihrem letzten Element möglich und erlaubt.

Allerdings ist die Verwendung dieser Sammlungsdatentypen für benutzerdefinierte Attribute nicht möglich. Benutzerdefinierte und vordefinierte Attribute besitzen keine eindeutige Zuordnung (Attribute existieren an einem Objekt in einer skalaren und feldhaften Variante) und erlauben einen unindizierten Zugriff auf den Standardwert.

6.1.1 Syntax von Ausdrücken

Liste und Hashes

Sammlungen mit den Datentypen hash, list, matrix, refvec oder vector können über die folgende Syntax innerhalb des Regelcodes definiert werden. Eine Definition im statischen Teil eines Dialogs oder Moduls ist nicht als Expression möglich, lediglich konstante Werte sind hier erlaubt. Ohne explizite Angabe eines Listen-Datentyps entsteht eine Liste vom Datentyp list. Bei Verwendung des Verweisoperators => entsteht automatisch ein hash (assoziatives Feld), wobei der Ausdruck vor dem => den Schlüssel bzw. Index definiert, der zweite den Wert.

Achtung

Aus Kompatibilitätsgründen genießt die Index-Expression Vorrang. Will man also eine zweielementige Liste mit zwei Integer-Werten aufbauen, so sollte man den Listendatentyp voranstellen.

Syntax

<Liste> = [ <Datentyp> ] '[' [ <Expression> { ',' <Expression> } ] ']'
<Hash-Liste> = [ <Datentyp> ] '[' [ <Expression> '=>' <Expression>
    { ',' <Expression> '=>' <Expression> } ] ']'

Beispiele

[1, .xleft, 17+4, Wi.Pb]
["ZDF" => 2, itoa(7) => 7]
matrix[ [1,1]=>"Vorname", [1,2]=>"Nachname", [1,3]=>"Telefonnr." ]

6.1.2 Listengröße und Standardwerte

Grundsätzlich hat jeder Sammlungsdatentyp eine aktuelle Größe, die sich entsprechend den gesetzten Werten ergibt. Wertelücken in diesem aktuell gültigen Indizierungsbereich gibt es nicht, lediglich ungesetzte Werte (siehe hierzu auch die Beschreibungen zu itemcount(), countof()).

Um die Konsistenz zu den bisherigen statischen lokalen Variablen herzustellen erlauben die Datentypen hash, list und matrix einen Standardwert.

Dieser wird angezeigt an ungesetzten Werte-Positionen innerhalb des aktuell gültigen Indizierungsbereiches bis zur aktuellen Größe. Bei hash-Datentypen wird bei gesetztem Standardwert dieser für alle möglichen Indexierungen zurückgeliefert.

Die Reihenfolge für den Zugriff auf die Standardwerte bei ungesetztem Wert an der Position <Row>,<Col> in einer Matrix M ist M[<Row>,<Col>]M[0,<Col>] → M[<Row>,0]M[0,0].

Die Zugriffsreihenfolge bis zum Standardwert bei ungesetztem Wert an <Index> in einer Liste L ist L[<Index>]L[0].

6.1.3 Zugriff und Zuweisungen von Sammlungen

Der Zugriff auf die indizierten Werte (Elemente) einer Sammlung erfolgt, wie bisher von lokalen Variablen oder vordefinierten und benutzerdefinierten Attribute gewohnt, über die []-Operation.

Ohne die []-Operation wird der gesamte Wert geholt oder gesetzt.

Achtung

Es ist zu beachten, dass ein Zugriff auf ein benutzerdefiniertes oder vordefiniertes Attribut ohne []-Index den Standardwert bzw. das skalare Attribut holt oder setzt. Möchte man alle Werte eines Attributs holen oder setzen, so sollten die Funktionen getvector() oder setvector() verwendet werden.

Beispiele

variable list Primes := [2,3,5,7,11,13];
variable vector[integer] Numbers;
variable hash Months := [1=>"Jan", 2=>"Feb", 3=>"Mar"];

print Primes[1];
Months[4] := "Apr";
Numbers := Primes;
Primes[0] := -1;
Primes := [17, 19, 23];

Das Ausgeben von Sammlungen über print oder sprintf() ist ebenso möglich. Dabei werden aber keine Standardwerte mit ausgegeben. Bei den Datentypen hash und matrix erfolgt die Ausgabe inklusive Index.

Besonderheiten refvec

Weiterhin ist zu beachten das der Datentyp refvec eine besondere Behandlung genießt, da er für die Eindeutigkeit der Werte sorgt und keine null-Werte speichert.

Bei einer indizierten Zuweisung einer schon vorhandenen object-ID wird die object-ID an der Position ersetzt und danach für die Eindeutigkeit gesorgt, was damit auch eine Verschiebung der schon vorhandenen object-ID an eine andere Position und eine Verkleinerung der refvec-Liste zur Folge haben kann.

Bei einer indizierten Zuweisung einer null wird die object-ID aus der refvec-Liste gelöscht und die nachfolgenden object-IDs rücken vor, was wiederum eine Verkleinerung der refvec-Liste zur Folge hat.

6.1.4 Automatische Konvertierung

In Zuweisungen oder Parameteraufrufen findet bei Sammlungen eine automatische Konvertierung in den verlangten Listentyp statt. Dabei werden alle Werte ohne Index in ihrer natürlichen Reihenfolge kopiert, wenn möglich inklusive der Standardwerte, z.B. [0] bei einer list-Variablen wird weitergegeben, wenn der Zieltyp ebenso einen Standardwert besitzt.

Ausnahme

Bei der Zuweisung von einem hash mit index-Datentyp an eine matrix wird der Index übernommen. Bei der umgekehrten Zuweisung von einer matrix an einen hash wird ebenso der Index mit übernommen. Will man dies verhindern, so sollte die eingebaute values()-Funktion verwendet werden.

6.1.5 Performanz

Grundsätzlich sollte bedacht werden, dass die Verwendung von Sammlungen (Gesamtwerte) innerhalb von Ausdrücken initial ein Kopieren der Werte erforderlich macht, dann aber bei lesenden Operationen lediglich Referenzen dieser Liste, also ohne weiteres Kopieren, Anwendung finden. So wird die nötige Performanz bei Umgang mit Sammlungen gewährleistet. Die Weitergabe an Applikationsfunktionen oder die Manipulation durch eingebaute Funktionen machen aber eine erneute Kopieraktion, unter Umständen mit einer Codepage-Konvertierung von String-Werten, erforderlich.

Insofern sollte bedacht werden, dass bei komplexen Ausdrücken, welche Sammlungen bearbeiten, durchaus temporär große Datenmengen auflaufen können. Die Kodierung und Aufteilung von Ausdrücken sollte mit Berücksichtigung der maximalen Listengrößen erfolgen.

6.1.6 Lokale und globale Variablen

Die Sammlungsdatentypen sind bei lokalen und bei globalen Variablen verfügbar. Eine Initialisierung einer globalen Sammlung ist ebenso mit konstanten Werten möglich.

Bisher konnten lokale, statische Variablen auch ein Feld oder assoziatives Feld sein, welches nur sehr beschränkt initialisiert werden konnte. Sammlungsdatentypen sind nun auch genauso für lokale und auch lokale, statische Variablen erlaubt. Der Initialisierungsausdruck ist dabei nicht mehr eingeschränkt.

Achtung Verhaltensänderung

Die bisherige Schreibweise für Felder und assoziative Felder für statische lokale Variablen ist wie bisher auch erlaubt und wird auf die Datentypen list oder hash abgebildet. Die statische Initialisierung über .<Bezeichner>[<Index>] := <Wert>; nach dem Variablenteil ist aber nicht mehr möglich um die Konsistenz zu anderen lokalen Variablen zu gewährleisten! Der Initialwert setzt den gesamten Variablenwert, und nicht wie früher nur den Standardwert!

Beispiel

dialog D

variable hash Prices := [ "iMac" => 1300, "Samsung Tab" => 300 ];
variable vector[string] Weekdays := ["Mon","Tue","Wed"];

on dialog start
{
  variable string Stations[integer] := [1=>"ARD", 2=>"ZDF"];
  variable hash Stations2 := [3=>"SWR", 4=>"RTL"];
  static variable list AllStations := join(Stations,Stations2);
  /* Nicht mehr erlaubt:
   * variable string Stations[integer] := "UNBEKANNT";
   * .Stations[1] := "ARD";
   * oder
   * static variable integer AssArray[string] := -1;
   * Stattdessen möglich:
   * static variable integer AssArray[string] := [nothing=>-1];
   */
  exit();
}

6.1.7 Vergleichsoperatoren

Für Sammlungen sind nur die Vergleichsoperatoren = und <> erlaubt.

Gleichheit herrscht bei folgenden Bedingungen:

  1. Der Datentyp muss gleich sein.
  2. Alle enthaltenen Werte bzw. Index/Wert-Paare müssen gleich sein, inklusive der Standardwerte.
  3. Die Anzahl der enthaltenen Werte und ihre Positionen müssen gleich sein.

Beim Vergleich zwischen einem String und einer Text-ID erfolgt der Vergleich auf String-Basis.

Bei der Verwendung von Vergleichsoperatoren ist insbesondere auf den Datentyp zu achten.

Beispiel

dialog D
window Wi {
  listbox Lb {
    .content[1] "Sat";
    .content[2] "Sun";
  }
}
on dialog start {
  variable list WeekendDays := ["Sat", "Sun"];
  variable hash DayNumber := ["Sat"=>6,"Sun"=>7];
  variable list Days;

  print WeekendDays = getvector(Lb, .content);
  print vector["Sat","Sun"] = getvector(Lb, .content);
  print values(WeekendDays) = values(getvector(Lb, .content));
  print WeekendDays = keys(DayNumber);
  Days := WeekendDays;
  WeekendDays[0] := "??";
  print Days=WeekendDays;
  exit();
}

Ausgabe

false => Datentyp verschieden (list<>vector)
true
true
true
false => WeekendDays hat einen Standardwert, Days aber nicht

6.1.8 Uninitialisierte Variablen

Wie bisher auch verhält sich der IDM beim Zugriff auf uninitialisierte Werte unterschiedlich. Wird auf eine uninitialisierte lokale oder statische Variable zugegriffen, erhält man nothing. Beim Zugriff auf eine uninitialisierte globale Variable (entspricht einem Variablen-Objekt) oder ein benutzerdefiniertes Attribut wird der Zugriff mit einem Fehler cannot get value verweigert.