Version 2003 (Geändert)
Datentypen der Variablen
4D kennt drei Variablentypen:
Lokale Variablen,
Prozessvariablen,
Interprozessvariablen.
Weitere Informationen dazu finden Sie im Abschnitt Variablen. Prozess- und Interprozessvariablen sind von der Struktur her dasselbe für den Compiler.
Da der Compiler nicht den Prozess bestimmen kann, in welchem die Variable verwendet wird, sollten Sie Prozessvariablen mit mehr Bedacht als Interprozessvariablen verwenden. Alle Prozessvariablen werden systematisch dupliziert, wenn ein neuer Prozess beginnt. Eine Prozessvariable kann in jedem Prozess einen anderen Wert haben, sie ist dagegen für die gesamte Datenbank vom gleichen Typ.
Variablentypen
Alle Variablen haben einen Typ. Wie im Abschnitt Datentypen beschrieben, gibt es 12 verschiedene Typen:
Boolean
Fester String
Datum
Ganzzahl
Lange Ganzzahl
Diagramm
Zeit
Bild
Numerisch (oder Zahl)
Zeiger
Text
BLOB
Es gibt neun verschiedene Typen von Arrays:
Boolean
Fester Text
Datum
Ganzzahl
Lange Ganzzahl
Bild
Zahl
Zeiger
Text
Symboldatei erstellen
Im interpretierten Modus kann sich der Datentyp einer Variablen ändern. Das ist möglich, da der Code interpretiert und nicht kompiliert wird. 4D interpretiert jede Anweisung separat und versteht ihren Kontext.
Im kompiliertem Modus ist die Situation anders. Während die Interpretation Zeile für Zeile abläuft, betrachtet der Kompilierungsprozess die Datenbank in ihrer Gesamtheit.
Der Compiler arbeitet folgendermaßen:
Er analysiert systematisch die Objekte in der Datenbank. Das sind Datenbank-, Projekt-, Formular-, Objektmethoden und Trigger.
Er durchläuft die Objekte, um den Datentyp jeder in der Datenbank verwendeten Variablen zu bestimmen und generiert eine Tabelle mit den Variablen und Methoden. Das ist die Symboldatei.
Sind die Datentypen von allen Variablen festgelegt, übersetzt bzw. kompiliert der Compiler die Datenbank. Das ist jedoch nur möglich, wenn er den Datentyp für jede der Variablen bestimmen kann.
Trifft der Compiler auf denselben Variablennamen für zwei unterschiedliche Datentypen, kann er keine Entscheidung treffen. Er muss nämlich, um ein Objekt zu typisieren und eine Speicheradresse zu vergeben, die exakte Kennung dieses Objekts wissen, d.h. Name und Datentyp. Der Compiler erstellt für jede kompilierte Datenbank eine Übersicht, die für jede Variable Name (oder Identifier) und Platzierung (oder Speicheradresse) sowie den gemäß dem Datentyp belegten Platz angibt. Diese Übersicht heißt Symboldatei. In den Einstellungen der Datenbank können Sie festlegen, ob diese Übersicht während dem Kompilieren in Form einer Textdatei angelegt werden soll.
Diese Übersicht wird auch für die automatische Erstellung von Compiler-Methoden verwendet.
Variablen typisieren
Der Compiler muss die Kriterien zum Erkennen von Variablen beachten.
Es gibt zwei Möglichkeiten:
Wurden die Variablen nicht typisiert, kann der Compiler das automatisch erledigen. Er bestimmt nach Möglichkeit, d.h. solange keine Zweideutigkeit vorliegt, den Typ der Variablen, nach der Art ihrer Verwendung. Schreiben Sie z.B.:
V1:= True
bestimmt der Compiler für die Variable V1 als Datentyp Boolean.
Schreiben Sie:
V2:= "Dies ist ein einfacher Satz"
bestimmt der Compiler für die Variable V2 als Datentyp Text.
Der Compiler kann den Datentyp einer Variablen auch in nicht so klaren Situationen bestimmen:
V3:= V1 `V3 ist vom selben Typ wie V1 V4:= 2*V2 `V4 ist vom selben Typ wie V2
Der Compiler bestimmt den Datentyp Ihrer Variablen auch über Aufrufe von 4D Befehlen und über Ihre Methoden. Übergeben Sie z.B. in einer Methode einen Parameter vom Typ Boolean und einen vom Typ Datum, weist der Compiler in der aufgerufenen Methode den lokalen Variablen $1 und $2 die Typen Boolean und Datum zu.
Bestimmt der Compiler den Datentyp durch Schlussfolgerung, weist er nie die eingrenzenden Typen Ganzzahl, Lange Ganzzahl oder Text zu, sondern standardmäßig immer den größtmöglichen Typ. Schreiben Sie z.B.:
Nummer:=4
weist der Compiler als Datentyp Zahl zu, obwohl 4 eine Ganzzahl ist. Dadurch kann der Wert in einem anderen Zusammenhang auch den Wert 4,5 haben.
Ist es sinnvoll, eine Variable als Ganzzahl, Lange Ganzzahl oder Text zu typisieren, können Sie eine Compiler Directive verwenden. Der Vorteil dabei ist, dass diese Datentypen weniger Speicher belegen und Operationen damit rascher ablaufen.
Haben Sie Ihre Variablen typisiert und sind Sie sicher, dass Ihre Typisierung kohärent und vollständig ist, können Sie in den Einstellungen zum Kompilieren explizit festlegen, dass der Compiler diese Arbeit nicht mehr ausführen muss. Sollte Ihre Typisierung nicht hundertprozentig richtig sein, meldet der Compiler beim Kompilieren Fehler und nennt die erforderlichen Änderungen.
Über Befehle der Compiler Direktiven können Sie explizit die in Ihrer Datenbank verwendeten Variablen deklarieren.
Sie werden folgendermaßen verwendet:
C_BOOLEAN(Var)
Solche Direktiven sagen dem Compiler, dass er eine Variable Var mit dem Typ Boolean anlegen soll. Eine Anwendung mit Compiler Direktiven erleichtert die Arbeit des Compilers und vermeidet Vermutungen.
Eine Compiler Direktive hat Vorrang vor Ableitungen, die auf Anweisungen oder der Verwendungsart beruhen.
Variablen, die mit der Compiler Direktive C_INTEGER definiert wurden, sind in der Tat dasselbe wie Variablen mit der Compiler Direktive C_LONGINT. Das sind in beiden Fällen Lange Ganzzahlen zwischen 2147483648 und +2147483647.
Compiler Direktiven verwenden
Compiler Direktiven sind in folgenden Fällen sinnvoll:
Der Compiler kann den Datentyp einer Variable nicht aus ihrem Kontext bestimmen,
Sie möchten nicht, dass der Compiler den Typ einer Variablen über ihre Verwendung bestimmt.
Außerdem sorgen Compiler Direktiven für eine Verringerung der Kompilierungszeit.
Zweideutige Fälle
Manchmal kann der Compiler den Datentyp einer Variablen nicht bestimmen. Ist dies der Fall, generiert er eine entsprechende Fehermeldung.
Es gibt drei Hauptgründe, die den Compiler den Datentyp nicht bestimmen lassen: Mehrfache Datentypen, Zweideutigkeit aufgrund einer gefolgerten Ableitung und keine Möglichkeit zur Bestimmung des Datentyps.
Mehrfache Datentypen
Hat eine Variable in den einzelnen Anweisungen unterschiedliche Datentypen, generiert der Compiler einen Fehler, der leicht zu beheben ist.
Der Compiler wählt die zuerst gefundene Variable und weist deren Datentyp wilkürlich dem nächsten Auftreten der gleichnamigen Variablen mit einem anderen Datentyp zu.
Hier ein einfaches Beispiel:
In Methode A,
Variable:=True
In Methode B,
Variable:="Der Mond ist rund"
Wird Methode A vor Methode B kompiliert, bewertet der Compiler die Anweisung Variable:="
Der Mond ist rund" als Änderung des Datentyps gegenüber der zuvor gefundenen Variablen. Der Compiler meldet, dass eine Retypisierung stattgefunden hat und erstellt eine Fehlermeldung. In den meisten Fällen können Sie das Problem beheben, indem Sie das zweite Auftreten der Variablen umbenennen.
Zweideutigkeit aufgrund einer gefolgerten Ableitung
In manchen Fällen kann der Compiler anhand des Ablaufs ableiten, dass der Typ des Objekts nicht geeignet ist. In diesem Fall müssen Sie die Variable explizit mit einer Compiler Direktiven typisieren.
Es folgt ein Beispiel, das mit Standardwerten für ein aktives Objekt arbeitet:
Sie können in einem Formular für folgende Objekte Standardwerte zuweisen: Combo Boxen, PopUp Menüs, Registerkarten, DropDown Listen, Menü/DropDown Listen und rollbare Bereiche unter Verwendung der Schaltfläche Bearbeiten für die Liste Werte (in der Eigenschaftenliste unter dem Thema Eingabekontrollen). Weitere Informationen dazu finden Sie im Handbuch 4th Dimension Designmodus. Die Standardwerte werden automatisch in ein Array geladen, das denselben Namen wie das Objekt hat.
Wird das Objekt nicht in einer Methode verwendet, kann der Compiler den Typ eindeutig als Array vom Typ Text ableiten.
Muss jedoch eine Initialisierung der Anzeige durchgeführt werden, könnte die Sequenz folgendermaßen lauten:
Case of : (Form event=On Load) MyPopUp:=2 ... End case
In diesem Fall tritt die Zweideutigkeit einbeim Analysieren der Methoden leitet der Compiler für das Objekt MyPopUp als Datentyp Zahl ab. In diesem Fall ist es notwendig, das Array in der Formular- oder einer Compiler-Methode explizit zu deklarieren:
Case of : (Form event=On Load) ARRAY TEXT(MyPopUp;2) MyPopUp:=2 ... End case
Keine Möglichkeit zur Bestimmung des Datentyps
Dieser Fall tritt ein, wenn eine Variable ohne Typisierung in einem Kontext verwendet wird, der keine Angaben zum Datentyp liefert. Hier kann nur eine Compiler Direktive dem Compiler helfen.
Dieses Phänomen tritt hauptsächlich in vier Kontexten auf:
- bei Verwendung von Zeigern (Pointer),
- wenn Sie einen Befehl mit mehr als einer Syntax verwenden,
- wenn Sie einen Befehl mit optionalen Parametern mit unterschiedlichen Datentypen verwenden,
- bei Verwendung einer 4D Methode, die über eine URL aufgerufen wird.
- Zeiger
Von einem Zeiger wird nicht erwartet, dass er etwas anderes als seinen eigenen Datentyp zurückgibt.
Nehmen wir folgende Sequenz:
Var1:=5.2 (1) Zeiger:=->Var1 (2) Var2:=Zeiger-> (3)
Obwohl (2) den Variablentyp definiert, auf den der Zeiger zeigt, ist der Typ von Var2 nicht festgelegt. Der Compiler erkennt während der Kompilation zwar einen Zeiger, hat jedoch keine Möglichkeit, zu erkennen, auf welchen Variablentyp er zeigt. Deshalb kann er den Datentyp von Var2 nicht ableiten. Hier ist eine Compiler Direktive erforderlich, zum Beispiel C_REAL(Var2).
- Befehle mit mehrfacher Syntax
Verwenden Sie eine Variable, der die Funktion Year of zugewiesen wurde, kann die Variable naturgemäß nur vom Typ Datum sein. Die Dinge liegen jedoch nicht immer so einfach. Nehmen wir folgendes Beispiel:
Der Befehl GET FIELD PROPERTIES lässt zwei Syntax-Arten zu:
GET FIELD PROPERTIES(TabelleNum;FeldNum;Typ;Länge;Indiziert)
GET FIELD PROPERTIES(FeldPtr;Typ;Länge;Indiziert)
Bei einem Befehl mit mehrfacher Syntax kann der Compiler nicht erraten, welche Syntax und Parameter Sie gewählt haben. Hier müssen Sie Compiler Direktiven einsetzen, um die im Befehl übergebenen Variablen zu typisieren, wenn diese nicht bereits an anderer Stelle in der Datenbank aufgrund ihrer Verwendung typisiert wurden.
- Befehle mit optionalen Parametern mit unterschiedlichen Datentypen
Bei einem Befehl mit mehreren optionalen Parametern mit unterschiedlichen Datentypen kann der Compiler nicht bestimmen, welcher optionale Parameter verwendet wurde. Nehmen wir folgendes Beispiel:
Der Befehl GET LIST ITEM lässt zwei optionale Parameter zu; den ersten als Lange Ganzzahl, den zweiten als Boolean.
Der Befehl kann verwendet werden in Form von:
GET LIST ITEM(Liste;EintragPos;EintragRef;EintragText;Unterliste;Erweitert)
oder in Form von:
GET LIST ITEM(list;EintragPos;EintragRef;EintragText;Erweitert)
Hier müssen Sie Compiler Direktiven einsetzen, um die im Befehl übergebenen optionalen Variablen zu typisieren, wenn diese nicht bereits an anderer Stelle in der Datenbank aufgrund ihrer Verwendung typisiert wurden.
- Über URL aufgerufene Methoden
Schreiben Sie 4D Methoden, die über eine URL aufgerufen werden müssen und verwenden Sie nicht $1 in der Methode, müssen Sie die Textvariable $1 explizit mit folgender Sequenz deklarieren:
C_TEXT($1)
In der Tat kann der Compiler nicht feststellen, ob die 4D Methode über eine URL aufgerufen wird.
Kompilierungszeit einsparen
Sind alle in der Datenbank vorkommenden Variablen explizit deklariert, muss der Compiler die Typisierung nicht überprüfen. In diesem Fall können Sie in den Einstellungen der Datenbank definieren, dass der Compiler nur die Übersetzung der Methode vornimmt. Das spart mindestens 50% an Zeit für die Kompilierung.
Code optimieren
Über Compiler Direktiven können Sie Ihre Methoden beschleunigen. Weitere Informationen dazu finden Sie im Abschnitt Tipps zur Optimierung. Nehmen wir an, Sie müssen einen Zähler über eine lokale Variable erhöhen. Deklarieren Sie die Variable nicht, geht der Compiler vom Typ Zahl aus. Deklarieren Sie die Variable als Lange Ganzzahl, arbeitet die kompilierte Datenbank effizienter. Auf einem Rechner beansprucht der Typ Zahl 8 Bytes, deklarieren Sie den Zähler als Lange Ganzzahl, benötigt er nur 4 Bytes. Das Hochzählen eines 8-Byte Zählers dauert also länger als das eines 4-Byte Zählers.
Compiler Direktiven anwenden
Compiler Direktiven lassen sich auf zwei Arten verwalten, je nachdem ob der Compiler Ihre Variablen typisieren soll oder nicht.
Vom Compiler typisierte Variablen
Soll der Compiler die Typisierung Ihrer Variablen prüfen oder sie selbst typisieren, ist die Platzierung der Direktiven einfach. Sie können je nach Ihrer Arbeitsweise zwischen zwei Möglichkeiten wählen:
Sie verwenden die Direktive in der Methode, wo die Variable zuerst erscheint, das hängt auch davon ob, ob es eine lokale, Prozess- oder Interprozessvariable ist. Stellen Sie sicher, dass die Direktive beim ersten Auftreten der Variablen in der zuerst auszuführenden Methode verwendet wird. Bedenken Sie, dass der Compiler beim Kompilieren die Methoden in der Reihenfolge hernimmt, wie sie in 4D erstellt wurden und nicht in der Reihenfolge, wie sie im Explorer angezeigt werden.
Bei systematischer Arbeitsweise gruppieren Sie alle Prozess- und Interprozessvariablen mit den verschiedenen Compiler Direktiven in der Datenbankmethode On Startup oder in einer Methode, die von der Datenbankmethode On Startup aufgerufen wird.
Für lokale Variablen gruppieren Sie die Direktiven an den Anfang der Methode, in welcher sie erscheinen.
Vom Entwickler typisierte Variablen
Soll der Compiler Ihre Typisierung nicht prüfen, müssen Sie ihm einen Code vorgeben, um die Compiler Direktiven zu identifizieren.
Die Konvention ist folgende:
Compiler Direktiven für Prozess- und Interprozessvariablen und die Parameter sollten in einer oder mehreren Methoden platziert werden. Ihr Name muss mit dem Schlüsselwort Compiler beginnen.
Sie können mit dem Compiler standardmäßig fünf Arten von Compilermethoden generieren. Das sind die Direktiven für Variablen, Arrays und Methodenparameter. Weitere Informationen dazu finden Sie im Handbuch 4D Designmodus.
Hinweis: Die Syntax zum Deklarieren dieser Parameter lautet:
Direktive (MethodenName;Parameter). Sie lässt sich nicht im interpretierten Modus ausführen.
Besondere Parameter
Über Datenbankmethoden empfangene Parameter
Wurden diese Parameter nicht ausdrücklich deklariert, macht dies der Compiler. Wollen Sie diese deklarieren, müssen Sie das innerhalb der Datenbankmethoden ausführen. Sie können diese Parameter Deklaration nicht in einer Compiler Methode schreiben.
Beispiel: Die Datenbankmethode On Web Connection empfängt sechs Parameter, $1 bis $6 vom Typ Text. Sie schreiben zu Beginn der Datenbankmethode:
C_TEXT($1;$2;$3;$4;$5;$6)
Trigger
Der Parameter $0 (Lange Ganzzahl), welcher das Ergebnis eines Triggers ist, wird vom Compiler typisiert, wenn der Parameter nicht ausdrücklich deklariert wurde. Wollen Sie ihn deklarieren, müssen Sie das innerhalb des Triggers ausführen. Sie können diese Parameter Deklaration nicht in einer Compiler Methode schreiben.
Objekte mit dem Formularereignis "On Drag Over"
Der Parameter $0 (Lange Ganzzahl), welcher das Ergebnis des Formularereignisses "On Drag Over"ist, wird vom Compiler typisiert, wenn der Parameter nicht ausdrücklich deklariert wurde. Wollen Sie ihn deklarieren, müssen Sie das innerhalb der Objektmethode tun. Sie können diese Parameter Deklaration nicht in einer Compiler Methode schreiben.
Hinweis: Der Compiler initialisiert nicht den Parameter $0. Sie müssen also, sobald Sie das Formularereignis "On Drag Over" verwenden, $0 initialisieren. Beispiel:
C_LONGINT($0) If (Form event=On Drag Over) $0:=0 ... If ($DataType=Is Picture) $0:=-1 End if ... End if
Compiler Direktive C_STRING
Der Befehl C_STRING verwendet eine andere Syntax als die anderen Direktiven, da er zusätzlich den Parameter max. Stringlänge zulässt.
C_STRING(Länge;Var1{;Var2; ;VarN})
Da C_STRING Strings mit fester Länge typisiert, geben Sie die max. Länge solcher Strings an. In einer kompilierten Datenbank müssen Sie die Länge des String mit einer Konstanten anstelle einer Variablen angeben.
In einer interpretierten Datenbank ist folgende Sequenz zulässig:
TheLength:=15 C_STRING(TheLength;TheString)
4D interpretiert TheLength und ersetzt TheLength durch deren Wert in der Compiler Direktive C_STRING.
Der Compiler benützt diesen Befehl jedoch beim Typisieren von Variablen ohne Beachten einer spezifischen Zuweisung. Da der Compiler nicht weiss, dass TheLength gleich 15 ist, kann er in der Symboldatei dafür keinen Platz bewahren. Deshalb sollten Sie im Hinblick auf die Kompilierung die Länge in einer Konstanten festlegen. Sie können zum Beispiel schreiben:
C_STRING(15;TheString)
Dieselbe Regel gilt für Arrays mit fester Länge, hier schreiben Sie folgende Anweisung:
ARRAY STRING(length;arrayName;size)
Der Parameter für die Länge des String im Array muss eine Konstante sein.
Sie können die Länge des String dagegen mit einer 4D Konstanten oder einem hexadezimalen Wert in den beiden folgenden Compiler Direktiven angeben. Zum Beispiel:
C_STRING(4DConstant;TheString) ARRAY STRING(4DConstant;TheArray;2) C_STRING(0x000A;TheString) ARRAY STRING(0x000A;TheArray;2)
Verwechseln Sie nicht die Länge eines alphanumerischen Feldes, das max. 80 Zeichen zulässt, mit einer Variablen mit festem String. Die max. Länge eines String, der in einer C_STRING Direktiven deklariert wurde oder zu einem ARRAY STRING gehört, liegt zwischen 1 und 255.
Hinweis: Mit der Syntax dieses Befehls können Sie verschiedene Variablen mit derselben Länge in einer einzelnen Zeile deklarieren. Wollen Sie mehrere Strings unterschiedlicher Länge deklarieren, führen Sie das in separaten Zeilen aus.
Vom Compiler zugelassener Spielraum
Compiler Direktiven entfernen jede Zweideutigkeit bei Datentypen und bei alphanumerischen Strings in Bezug auf die Länge. Auch wenn eine gewisse Striktheit notwendig ist, muss das nicht heissen, dass der Compiler überhaupt keine Inkonsistenz toleriert.
Weisen Sie zum Beispiel einer Variablen, die als Ganzzahl deklariert wurde, einen Wert vom Typ Zahl zu oder einer Variablen, die als String mit 10 Zeichen deklariert wurde, einen String mit 30 Zeichen, sieht der Compiler in beiden Fällen keinen Typkonflikt und weist die Werte gemäß den Direktiven zu. Wenn Sie also schreiben:
C_INTEGER(vInteger) vInteger:=2.5
betrachtet der Compiler das nicht als Konflikt des Datentyps, der eine Kompilierung verhindert; vielmehr rundet er einfach auf den nächstgelegenen Wert auf (3 anstatt 2.5).
Ist der deklarierte String kürzer als der, mit dem Sie arbeiten, nimmt der Compiler nur die Anzahl Zeichen, die in der Direktiven angegeben ist. In der folgenden Sequenz:
C_STRING(10;MyString) MyString:="Es ist ein schöner Tag"
nimmt der Compiler nur die ersten 10 Zeichen der Konstanten, also "Es ist ein".
Referenz
Einzelheiten zur Syntax, Fehlermeldungen, Richtlinien zur Typisierung, Tipps zur Optimierung.