• Keine Ergebnisse gefunden

Eine Datendefinition (<data definition>) definiert zum einen eine Menge möglicher Werte des Datentyps (die Sorte15, engl. sort), zum anderen eine Menge von Operationen auf der Sorte.

Es gibt mehrere Arten von Datendefinitionen:

<data definition> =

<data type definition> | <interface definition> | <syntype definition> | <synonym definition>

Hierbei werden nur mit Hilfe einer <data type definition> tatsächlich neue Sorten eingeführt.

Eine <interface definition> wählt aus der Menge aller Pid-Werte eine Teilmenge aus (nämlich die Menge aller der Agenten, die diese Schnittstelle besitzen). Pid-Sorten werden also nicht di-rekt durch eine Typdefinition eingeführt, sondern als Seiteneffekt einer <interface definition>.

Eine <syntype definition> definiert einen Aliasnamen für einen existierenden Datentyp, und schränkt eventuell die Menge der gültigen Werte ein.

Neben den Pid-Sorten gibt es zwei verschiedene Kategorien von Sorten: Die Objektsorten, deren Werte als Referenzen übergeben werden, und die Wertesorten, die einer Kopiersemantik unterliegen.

Eine <synonym definition> definiert keinen Datentyp, sondern eine symbolische Konstante (ein Synonym). <synonym definition> ist nur deshalb eine Alternative für <data definition>, weil Synonyme syntaktisch an allen Stellen erlaubt sind, an denen auch alle anderen Datende-finitionen erlaubt sind.

Jede Datendefinition trägt einen Namen. Die von der Datendefinition eingeführte oder ein-geschränkte Sorte trägt den gleichen Namen. Mit dem Konstrukt <sort> kann man auf eine Sor-te Bezug nehmen:

<sort> = <basic sort> | <anchored sort> | <expanded sort> | <reference sort> | <pid sort>

Üblicherweise erfolgt eine solche Bezugnahme durch den Namen der Sorte. Beispielsweise wird in der Deklaration

dcl counter Integer;

Bezug auf die (vordefinierte) Sorte Integer genommen. In diesen Fällen handelt es sich um die Regel <basic sort>:

<basic sort> = <sort identifier>16 | <syntype>

Unter Umständen kann der Name einer Sorte, die beispielsweise als Rückgabetyp einer Ope-ration auftritt, nicht angegeben werden, weil sich der Rückgabetyp der OpeOpe-ration bei Speziali-sierung des Datentyps ändert. In diesem Fall kann man mit dem Schlüsselwort this die Sorte flexibel angeben. Mit der Spezialisierung des Datentyps ändert sich auch automatisch jedes Auftreten dieses Sortennamens:

object type Base;

15. Der Begriff der Sorte wird üblicherweise im Zusammenhang mit abstrakten Datentypen verwendet, um die mathematischen Objekte zu bezeichnen, die als Argumente und Ergebnis einer Operationssignatur erscheinen. Im streng algebraischen Sinne sind Sorten nicht selber Mengen, sondern symbolische Namen, denen eine Trägermenge zugeordnet ist.

16. Der unterstrichene Teil eines Hilffsymbols der Grammatik bezeichnet eine sogenannte „semantische Kategorie“. Syntaktisch erlaubt die Regel <basic sort> die Angabe beliebiger <identifier>. Für diese wird aber durch die semantische Kategorie gefordert, dass es sich um Sortenbezeichner handelt.

methods

merge(this) -> this;

endobject type;

object type Derived inherits Base;

endobject type;

In diesem Beispiel definiert der Typ Base eine Methode merge, die ein Argument der glei-chen Sorte erwartet und ein ebensolches Ergebnis liefert. Der Typ Derived ist eine Spezialisie-rung des Typs Base. Wird nun die Methode merge für ein Objekt der Sorte Base aufgerufen, so ist der Rückgabewert ebenfalls aus der Sorte Base. Erfolgt der Aufruf jedoch für ein Objekt der Sorte Derived, so muss das Argument ebenfalls aus der Sorte Derived sein, und auch das Ergeb-nis ist von der Sorte Derived. In der abstrakten Syntax wird eine solche Sortenreferenz als <an-chored sort> bezeichnet. Die Referenz enthält optional den Namen der Basissorte:

<anchored sort> :: [<basic sort>]

Wenn eine Sorte als Objektsorte definiert wurde (wie in obigem Beispiel die Sorten Base und Derived), dann werden die Werte der Sorte als Referenzen bei Zuweisungen und als Argument von Operatoren übergeben. Es ist jedoch möglich, an ausgewählten Stellen eine Übergabe per Wert festzulegen. Dazu schreibt man vor den Sortennamen das Schlüsselwort value:

dcl base_value value Base;

Zuweisungen von und an die Variable base_value erfolgen nun durch Kopienbildung. Eine solche Konstruktion wird in der abstrakten Syntax 0 als <expanded sort> repräsentiert:

<expanded sort> :: <basic sort>

Genauso ist es möglich, für eine durch Kopiersemantik definierte Sorte Referenzsemantik festzulegen. Dies erfolgt analog durch das Schlüsselwort object. So definierte Variablen und Parameter werden bei Belegung mit einer Referenz initialisiert. Zugriffe liefern dementspre-chend Referenzen. Dieses Konstrukt wird in der abstrakten Syntax als <reference sort> reprä-sentiert:

<reference sort> :: <basic sort>

Schließlich kann sich ein Sortenname auch auf eine Pid-Sorte beziehen:

<pid sort> = <sort<identifier>

In diesem Fall ergibt sich die Information, dass es sich um eine Pid-Sorte handelt, allein durch den Bezeichner (<identifier>): dieser muss eine Schnittstellendefinition bezeichnen. In den anderen Fällen (<anchored sort>, <expanded sort> und <reference sort>) ergibt sich die Art der Sorte nicht allein aus dem enthaltenen Sortenbezeichner, da die jeweilige Konstruktion ja gerade eine Modifikation der Sorte vornimmt. Deshalb wird also das Hilfssymbol <pid sort> als Synonym für <identifier> definiert, während die Symbole <anchored sort>, <expanded sort>

und <reference sort> eigene Knoten der abstrakten Syntax bilden.

Eigentliche Datentypdefinitionen werden durch die Konstrukte object type und value type definiert. Die abstrakte Syntax für Datentypdefinitionen lautet

<data type definition> ::

<package use clause>* <type preamble> <data type heading> [<data type specialization>]

[ <data type definition body> ]

Mit Hilfe der Liste <package use clause>* kann man Pakete referenzieren, auf deren Inhalt in der Datentypdefinition Bezug genommen werden kann. Das Konstrukt <type preamble>

kann eines der Schlüsselwörter virtual oder abstract enthalten. Dementsprechend ist der ent-stehende Datentyp virtuell oder abstrakt. Ein virtueller Datentyp ist ein Typ, der in einer Spezi-alisierung seines Containers (also beispielsweise des Prozesstyps, in dem er definiert ist) durch

einen anderen Typ ausgetauscht werden kann. Ein abstrakter Datentyp ist ein Typ, von dem kei-ne Instanzen gebildet werden könkei-nen.

Das Konstrukt <data type heading> gibt die Art der Datentypdefinition (Objekttyp oder Wer-tetyp), den Namen, eventuelle Kontextparameter und Einschränkungen bei der Redefinition ei-nes virtuellen Typs an:

<data type heading> ::

<data type kind> <data type<name> <formal context parameter>* [<virtuality constraint>]

<data type kind> = value | object

Durch Angabe von Kontextparametern erhält man parametrisierte Typen. Kontextparameter können beispielsweise weitere Datentypen sein, die innerhalb des gerade definierten Datentyps als Feldtypen auftreten. Diese Kontextparameter können bei Spezialisierung gebunden werden.

Die aktuellen Kontextparameter geben dann den tatsächlichen Feldtyp an. Darauf wird im Ab-schnitt 6.3 näher eingegangen.

Der eigentliche Körper der Datentypdefinition wird durch die Regel <data type definition body beschreiben>:

<data type definition body> ::

<entity in data type>* [<data type constructor>] <operations> [<default initialization>]

In einer Datentypdefinition können weitere Definitionen (sog. entities) enthalten sein. Wel-che diese genau sind, wird durch die Regel <entity in data type> beschrieben

<entity in data type> =

<data type definition> | <syntype definition> | <synonym definition> | <exception definition>

Da Daten in SDL passiv sind, ist die Definition aktiver Komponenten (also von Agenten) in Datentypen nicht erlaubt; erlaubt sind lediglich Definitionen weiterer Daten und Ausnahmen.

Den enthaltenen Definition folgt optional ein Typkonstruktor (<data type constructor>), der in Abschnitt 6.5 erläutert wird. Er gibt an, auf welche Weise dieser Datentyp aus anderen kon-struiert ist – es handelt sich also nicht um Konstruktoren für Instanzen, wie sie aus anderen Pro-grammiersprachen bekannt sind.

Dem Typkonstruktor folgt die Deklaration von Operationen (Operatoren und Methoden).

Dabei werden zuerst die Signaturen angegeben, gefolgt von den Definitionen:

<operations> :: <operation signatures> <textual operation reference>* <operation definitions>*

Falls einige Operationen nicht textuell in der Datentypdefinition definiert sind, so muss in der Typdefinition zumindest eine Operationsreferenz (<textual operation reference>) auftau-chen.

Optional kann eine Datentypdefinition eine Defaultinitialisierung (<default initialization>) enthalten. Diese Initialisierung wird immer dann als Initialwert verwendet, wenn eine Variable ohne speziellen Initialwert definiert wurde:

<default initialization> ::[<virtuality>] [<constant expression>]

Beispiel 11. Eine Datentypdefinition, die von allen Konstrukten Gebrauch macht, ist folgender Objekttyp DT:

use TypesLibrary/Color; /* package use clause */

virtual object type DT<type P> /* type preamble, data type kind, name, formal context parameter */

atleast BT1 /* virtuality constraint */

inherits BT2; /* specialization */

exception /* entity in data type */

InvalidColor(Color);

struct /* data type constructor private field1 Color;

optional field2 P;

methods /* operation signatures */

getP() -> P;

setColor(Color) raises InvalidColor;

method setColor; referenced; /* textual operation reference */

method getP() /* operation definition */

{ return field2;

} default (. Red .); /* Default initialization */

endobject type;

In diesem Typ ist DT eine Spezialisierung von BT2. Redefinitionen von DT müssen nicht not-wendigerweise auch Spezialisierungen von DT sein – es reicht, wenn sie Spezialisierungen von BT1 sind. Daraus ergibt sich implizit, dass BT2 eine Spezialisierung von BT1 ist; ande-renfalls würde ja DT seine eigene Virtualitätsbedingung verletzen.