Version 2003 (Geändert)
Der Compiler geht davon aus, dass die üblichen Syntaxregeln für 4D Befehle angewandt werden. Für Datenbanken, die kompiliert werden sollen, sind keine besonderen Änderungen erforderlich.
Dieser Abschnitt weist auf bestimmte Eigenheiten und spezifische Details hin:
Einige Befehle, die den Datentyp einer Variablen beeinflussen, können bei Unachtsamkeit zu Datenkonflikten führen.
Da manche Befehle verschiedene Arten von Syntax oder Parameter zulassen, ist es von Vorteil, zu wissen, welche Variante sich am besten eignet.
Strings
Ascii (Zeichen)
Für Befehle, die mit Strings arbeiten, benötigt nur die Funktion Ascii besondere Aufmerksamkeit. Im interpretierten Modus können Strings Zeichen beinhalten oder leer sein.
Im kompilierten Modus können Sie keinen leeren String übergeben.
Übergeben Sie einen leeren String und ist das in Ascii übergebene Argument eine Variable, kann der Compiler beim Kompilieren keinen Fehler entdecken.
Kommunikation
SEND Variable(Variable)
RECEIVE VARIABLE(Variable)
Diese beiden Befehle dienen zum Schreiben und Empfangen von Variablen, die an die Festplatte gesendet wurden. Variablen werden in diesen Befehlen als Parameter übergeben.
Der übergebene Parameter muss immer vom selben Datentyp sein. Nehmen wir an, Sie wollen eine Liste mit Variablen an eine Datei senden. Um auszuschliessen, dass der Datentyp versehentlich geändert wird, empfehlen wir, den Datentyp der Variablen in der Titelzeile der Liste anzugeben. So erhalten Sie beim Empfangen der Variablen zu Beginn immer einen Indikator. Rufen Sie dann den Befehl RECEIVE VARIABLE auf, wird der Transfert über eine Case of Anweisung ausgeführt.
Beispiel:
SET CHANNEL(12;"Datei") If (OK=1) $Type:=Type([Client]Total_TO) SEND VARIABLE($Type) For($i;1;Records in selection) $Send_TO:=[Client]Total_TO SEND VARIABLE($Send_TO) End for End if SET CHANNEL(11) SET CHANNEL(13;"MeineDatei") If (OK=1) RECEIVE VARIABLE($Type) Case of :($Type=Is String Var) RECEIVE VARIABLE($String) `Empfangene Variable bearbeiten :($Type=Is Real) RECEIVE VARIABLE($Real) `Empfangene Variable bearbeiten :($Type=Is Text) RECEIVE VARIABLE($Text) `Empfangene Variable bearbeiten End case End if SET CHANNEL(11)
Strukturzugriff
Field (field pointer) oder (table number;field Numerisch)
Table(table pointer) oder (table Numerisch) oder (field pointer)
Diese beiden Funktionen geben Werte mit verschiedenen Datentypen zurück, abhängig von den übergebenen Parametern:
Übergeben Sie der Funktion Table einen Zeiger, ist das Ergebnis vom Typ Zahl
Übergeben Sie der Funktion Table eine Zahl, wird als Ergebnis ein Zeiger zurückgegeben.
Beide Funktionen reichen für den Compiler nicht aus, um den Datentyp des Ergebnisses zu bestimmen. Verwenden Sie in solchen Fällen eine Compiler Direktive, um jegliche Zweideutigkeit auszuschliessen.
Dokumente
Beachten Sie, dass Referenzen auf Dokumente, die von den Funktionen Open document, Append document und Create document zurückgegeben werden, vom Typ Zeit sind.
Math
Mod (value;divider)
Der Ausdruck "25 modulo 3" lässt sich auf zwei Arten in 4D darstellen:
Variable:=Mod(25;3)
oder
Variable:=25%3
Der Compiler erkennt den Unterschied zwischen ihnen: Mod gilt für alle Zahlen, der Operator % dagegen nur für Ganzzahlen und Lange Ganzzahlen. Übersteigt der Operand die Reichweite des Typs Lange Ganzzahl, ist das zurückgegebene Ergebnis falsch.
Ausnahmen
IDLE
ON EVENT CALL (Methode{; ProzessName})
ABORT
ON EVENT CALL
Der Befehl IDLE wurde in die Programmiersprache von 4D integriert, um Ausnahmen zu verwalten. Verwenden Sie diesen Befehl in Verbindung mit dem Befehl ON EVENT CALL.
Sie können ihn als Direktive zur Ereignisverwaltung verwenden.
Nur der Kernel von 4D kann ein Systemereignis ausfindig machen. (Mausklick, Aktivität auf Tastatur, usw.). In den meisten Fällen werden Aufrufe des Kernel vom kompilierten Code selbst initiiert, in einer für den Benutzer transparenten Weise.
Wartet 4D dagegen passiv auf ein Ereignis zum Beispiel in einer Warteschleife ist klar, dass es keinen Aufruf geben wird.
Beispiel unter Windows
`Methode Mausklick If (MouseDown=1) <>vTest:=True ALERT("Jemand hat die Maustaste betätigt") End if `Methode Warten <>vTest:=False ON EVENT CALL("Mausklick") While(<>vTest=False) `Warteschleife für Ereignis End while ON EVENT CALL("")
In diesem Fall fügen Sie den Befehl IDLE folgendermaßen ein:
`Methode Warten <>vTest:=False ON EVENT CALL("Mausklick") While(<>vTest=False) IDLE `Kernel Aufruf, um ein Ereignis aufzuspüren End while ON EVENT CALL("")
ABORT
Verwenden Sie diesen Befehl nur in Projektmethoden zur Fehlerverwaltung. Er arbeitet genauso wie in 4D, außer in einer Methode, die von folgenden Befehlen aufgerufen wurde: EXECUTE, APPLY TO SELECTION oder APPLY TO SUBSELECTION. Versuchen Sie, derartige Situationen zu vermeiden.
Arrays
Der Compiler bestimmt den Datentyp eines Array über folgende 4D Befehle:
COPY ARRAY(Quelle;Ziel)
SELECTION TO ARRAY(Feld;Array)
ARRAY TO SELECTION(Array;Feld)
SELECTION RANGE TO ARRAY(Start;Ende;Feld;Array)
LIST TO ARRAY(Auswahlliste;Array{; itemRefs})
ARRAY TO LIST(Array;Auswahlliste{; itemRefs})
DISTINCT VALUES(Feld;Array)
COPY ARRAY
Dieser Befehl akzeptiert zwei Arten von Array-Parametern. Ist einer der Array-Parameter nicht an anderer Stelle deklariert, bestimmt der Compiler den Datentyp des nicht deklarierten Array anhand des deklarierten Typs.
Die Ableitung erfolgt auf zwei Arten:
Das typisierte Array ist der erste Parameter. Der Compiler weist den Datentyp des ersten Array in dem zweiten Array zu.
Das deklarierte Array ist der zweite Parameter. Der Compiler weist hier den Datentyp des zweiten Array dem ersten zu.
Da der Compiler bei Datentypen strikt ist, lässt sich COPY ARRAY nur von einem Array eines bestimmten Datentyps zu einem Array desselben Typs ausführen.
Wollen Sie also ein Array mit Elementen kopieren, die einen ähnlichen Datentyp haben, z.B. Ganzzahl, Lange Ganzzahl und Zahl oder Text und String oder Strings mit unterschiedlichen Längen, müssen Sie die Elemente einzeln kopieren.
Nehmen wir an, Sie wollen Elemente von einem Array Typ Ganzzahl zu einem Array Typ Zahl kopieren. Gehen Sie folgendermaßen vor:
$Size:=Size of array(ArrInt) ARRAY REAL(ArrReal;$Size) `Setzen Sie für das Array Typ Zahl dieselbe Grösse wie für das Array Typ Ganzzahl For($i;1;$Size) ArrReal{$i}:=ArrInt{$i} `Kopieren Sie jedes Element End for
Bedenken Sie, dass Sie während dem Prozess die Anzahl der Dimensionen eines Array nicht verändern können. Kopieren Sie ein eindimensionales Array in ein zweidimensionales Array, erzeugt der Compiler eine Fehlermeldung.
SELECTION TO ARRAY, ARRAY TO SELECTION, DISTINCT VALUES, SELECTION RANGE TO ARRAY
Diese Befehle müssen im interpretierten Modus nicht deklariert werden. Ein nicht typisiertes Array erhält den Datentyp des Feldes, das im Befehl angegeben ist.
Schreiben Sie:
SELECTION TO ARRAY([MyTable]IntField;MyArray)
ist MyArray eindimensional mit dem Typ Lange Ganzzahl (in der Annahme, dass IntField vom Typ Ganzzahl ist).
Wurde das Array typisiert, stellen Sie sicher, dass das Datenfeld vom selben Datentyp ist. Ganzzahl, Lange Ganzzahl und Zahl sind zwar ähnliche Typen, jedoch nicht vollkommen gleich. Bei den Datentypen Text und String gibt es dagegen mehr Spielraum. Wurde ein Array nicht vorab typisiert und wenden Sie einen Befehl an, der als Parameter ein Feld vom Typ String enthält, wird dem Array standardmäßig als Typ Text zugewiesen. Wurde das Array zuvor als String bzw. Text typisiert, befolgen diese Befehle Ihre Direktiven.
Dasselbe gilt für Felder vom Typ Text Ihre Direktiven haben Vorrang.
Bedenken Sie, dass Sie die Befehle SELECTION TO ARRAY, SELECTION RANGE TO ARRAY, ARRAY TO SELECTION und DISTINCT VALUES nur in eindimensionalen Arrays verwenden können.
Der Befehl SELECTION TO ARRAY hat auch eine zweite Syntax, nämlich:
SELECTION TO ARRAY(Tabelle;Array).
In diesem Fall ist die Variable MyArray ein Array vom Typ Lange Ganzzahl. Dasselbe gilt auch für den Befehl SELECTION RANGE TO ARRAY.
LIST TO ARRAY, ARRAY TO LIST
Für die Befehle LIST TO ARRAY und ARRAY TO LIST treffen nur zwei Arten von Arrays zu:
eindimensionales Array vom Typ String und
eindimensionales Array vom Typ Text.
Für diese Befehle muss das als Parameter übergebene Array nicht typisiert sein. Es wird standardmäßig als Array vom Typ Text typisiert. Wurde es zuvor als String bzw. Text typisiert, befolgen diese Befehle Ihre Direktiven.
Zeiger in Befehlen mit Arrays
Der Compiler kann keinen Datentyp aufspüren, wenn Sie in einem Befehl mit Array Deklaration einen dereferenzierten Zeiger als Parameter übergeben. Schreiben Sie:
SELECTION TO ARRAY([Table]Field;Pointer->)
wobei Pointer-> für ein Array steht, kann der Compiler nicht prüfen, ob Feldtyp und Array-Typ identisch sind. Solche Konflikte müssen Sie selbst ausschliessen, indem Sie das Array typisieren, auf das sich der Zeiger bezieht.
Der Compiler zeigt eine Warnung, wenn er eine Anweisung mit einer Array-Deklaration findet, in der ein Parameter ein Zeiger ist. Diese Meldungen sind hilfreich beim Suchen solcher Datentypkonflikte.
Lokale Arrays
Verwendet Ihre Datenbank lokale Arrays, d.h. sie werden nur in der Methode erkannt, in welcher sie erstellt wurden, müssen diese vor der Verwendung ausdrücklich in 4th Dimension typisiert werden.
Dazu verwenden Sie die Befehle für Arrays, z.B. ARRAY REAL, ARRAY INTEGER, etc.
Erstellt eine Methode z.B. ein lokales Array vom Typ Ganzzahl mit 10 Elementen, müssen Sie zuvor das Array wie folgt typisieren:
ARRAY INTEGER($MyArray;10)
Programmiersprache
Get pointer(varName)
Typ (Objekt)
EXECUTE(statement)
TRACE
NO TRACE
Get pointer
Die Funktion Get pointer gibt einen Zeiger auf den ihm übergebenen Parameter zurück. Nehmen wir an, Sie möchten ein Array mit Zeigern initialisieren. Jedes Element im Array zeigt auf eine bestimmte Variable. Unser Beispiel enthält 12 Variablen mit Namen V1, V2, V12. Sie können schreiben:
ARRAY POINTER(Arr;12) Arr{1}:=->V1 Arr{2}:=->V2 Arr{12}:=->V12
Sie können auch schreiben:
ARRAY POINTER(Arr;12) For($i;1;12) Arr{$i}:=Get pointer("V"+String($i)) End for
Am Ende dieser Operation enthalten Sie ein Array mit Zeigern, in dem jedes Element auf eine Variable Vi zeigt.
Sie können beide Sequenzen kompilieren. Werden die Variablen V1 bis V12 jedoch nicht in der Datenbank an anderer Stelle ausdrücklich verwendet, kann der Compiler sie nicht typisieren. Sie müssen sie also explizit an anderer Stelle verwenden bzw. typisieren. Es gibt zwei Möglichkeiten:
Sie typisieren V1, V2, V12 über eine Compiler Direktive:
C_LONGINT(V1;V2;V3;V4;V5;V6;V7;V8;V9;V10;V11;V12)
Sie weisen diese Variablen in einer Methode zu:
V1:=0 V2:=0 V12:=0
Typ (Objekt)
Da jede Variable in einer kompilierten Datenbank nur einen Datentyp hat, scheint diese Funktion überflüssig. Der Einsatz von Zeigern ist jedoch hilfreich, z.B. wenn Sie den Datentyp der Variablen benötigen, auf die sich ein Zeiger bezieht. Da Zeiger flexibel sind, können Sie nicht immer sicher sein, auf welche Objekte sie jeweils zeigen.
EXECUTE
Dieser Befehl bietet im interpretierten Modus Vorteile, die nicht in den kompilierten Modus übernommen werden.
Hier wird ein Methodenname, der diesem Befehl als Parameter übergeben wird, interpretiert. Deshalb vermissen Sie einige der Vorteile, die der Compiler bietet, die Syntax Ihrer Parameter lässt sich nicht überprüfen.
Ausserdem können Sie keine lokalen Variablen als Parameter übergeben.
Sie können diesen Befehl durch eine Reihe von Anweisungen ersetzen. Hierzu zwei Beispiele:
Wir gehen von folgender Sequenz aus:
i:= FormFunc EXECUTE("INPUT FORM (Form"+String(i)+")")
Sie lässt sich ersetzen durch:
i:=FormFunc VarForm:="Form"+String(i) INPUT FORM(VarForm)
Anderes Beispiel:
$Num:=SelPrinter EXECUTE("Print"+$Num)
Hier lässt sich EXECUTE ersetzen durch Case of:
Case of : ($Num=1) Print1 : ($Num=2) Print2 : ($Num=3) Print3 End case
Der Befehl EXECUTE lässt sich immer ersetzen. Da die auszuführende Methode aus der Liste der Projektmethoden in der Datenbank oder den 4th Dimension Befehlen ausgewählt wird, gibt es eine feste Anzahl an Methoden. Folglich lässt sich EXECUTE immer ersetzen durch eine Anwendung Case of oder einen anderen Befehl. Dadurch wird Ihr Code auch rascher ausgeführt.
TRACE, NO TRACE
Diese beiden Befehle werden beim Debuggen verwendet. Sie haben in einer kompilierten Datenbank keine Funktion. Sie können sie jedoch in Ihren Methoden beibehalten, der Compiler ignoriert sie einfach.
Variablen
Undefined(Variable)
SAVE VARIABLES(document;variable1{; variable2 })
LOAD VARIABLES(document;variable1{; variable2 })
CLEAR Variable(Variable)
Undefined
Da der Compiler die Typisierung ausführt, kann eine Variable im kompilierten Modus nie undefiniert sein. Tatsächlich sind alle Variablen definiert, wenn die Kompilierung abgeschlossen ist. Von daher gibt die Funktion Undefined immer Falsch zurück, egal, welcher Parameter übergeben wurde.
Hinweis: Über die Funktion Compiled application können Sie feststellen, ob Ihre Anwendung im kompilierten Modus läuft.
SAVE VARIABLES, LOAD VARIABLES
Im interpretierten Modus können Sie prüfen, ob das Dokument vorhanden ist, indem Sie testen, ob eine der Variablen nach Ausführen des Befehls LOAD VARIABLES undefiniert ist. Das ist in einer kompilierten Datenbank nicht möglich, da die Funktion Undefined immer Falsch zurückgibt.
Diesen Test können Sie im interpretierten oder kompilierten Modus folgendermaßen durchführen:
1. Sie initialisieren die Variablen, die Sie von einem Wert empfangen, der kein legaler Wert für irgendeine der Variablen ist.
2. Sie vergleichen eine der empfangenen Variablen mit dem Wert der Initialisierung nach Ausführen von LOAD VARIABLES.
Sie schreiben folgende Methode:
Var1:="xxxxxx" `"xxxxxx" ist ein Wert, der nicht über LOAD VARIABLES zurückgegeben werden kann Var2:="xxxxxx" Var3:="xxxxxx" Var4:="xxxxxx" LOAD VARIABLES("Dokument";Var1;Var2;Var3;Var4) If(Var1="xxxxxx") `Dokument nicht gefunden Else `Dokument gefunden End if
Variable CLEAR
Diese Routine verwendet im interpretierten Modus zwei unterschiedliche Syntaxarten:
CLEAR VARIABLE(variable)
CLEAR VARIABLE("a")
Im kompilierten Modus initialisiert die erste Syntax von CLEAR VARIABLE(variable) erneut die Variable (für Zahl Setzen auf Null; leerer String für Zeichenkette oder Text, etc.), da im kompilierten Modus keine Variable undefiniert sein kann.
Aus diesem Grund setzt CLEAR VARIABLE im kompilierten Modus keinen Speicher frei, mit Ausnahme von vier Fällen: Variablen vom Typ Text, Bild, BLOB und Array.
CLEAR VARIABLE bewirkt für ein Array dasselbe wie eine neue Deklaration des Array, dessen Größe auf Null gesetzt wird.
Für ein Array MyArray, dessen Elemente vom Typ Ganzzahl sind, bewirkt CLEAR VARIABLE(MyArray) dasselbe wie einer der folgenden Ausdrücke:
ARRAY INTEGER(MyArray;0) `Wenn es ein eindimensionales Array ist ARRAY INTEGER(MyArray;0;0) `Wenn es ein zweidimensionales Array ist
Die zweite Syntax CLEAR VARIABLE("a") ist mit dem Compiler nicht kompatibel, da er auf Variablen über deren Adresse und nicht über deren Namen zugreift.
Zeiger für bestimmte Befehle
Nachfolgende Befehle haben folgendes gemeinsam: Sie erlauben einen optionalen ersten Parameter [Tabelle], der zweite Parameter kann ein Zeiger sein.
ADD TO SET | LOAD SET |
APPLY TO SELECTION | LOCKED ATTRIBUTES |
COPY NAMED SELECTION | ORDER BY |
CREATE EMPTY SET | ORDER BY FORMULA |
CREATE SET | OUTPUT FORM |
CUT NAMED SELECTION | PAGE SETUP |
DIALOG | Print form |
EXPORT DIF | PRINT LABEL |
EXPORT SYLK | QR REPORT |
EXPORT TEXT | QUERY |
GOTO RECORD | QUERY BY FORMULA |
GOTO SELECTED RECORD | QUERY SELECTION |
GRAPH TABLE | QUERY SELECTION BY FORMULA |
IMPORT DIF | REDUCE SELECTION |
IMPORT SYLK | RELATE MANY |
IMPORT TEXT | REMOVE FROM SET |
INPUT FORM |
Im kompilierten Modus ist es leicht, den optionalen Parameter [Tabelle] zurückzugeben. Wird dagegen in einem dieser Befehle als erster Parameter ein Zeiger übergeben, weiss der Compiler nicht, auf was sich der Zeiger bezieht; er behandelt ihn als Zeiger auf eine Tabelle.
Nehmen wir den Befehl QUERY mit folgender Syntax:
QUERY({table{;formula{;*}})
Das erste Element des Parameters formula muss ein Feld sein.
Schreiben Sie:
QUERY(PtrField->=True)
sucht der Compiler nach einem Symbol, das im zweiten Element ein Feld darstellt. Findet er das Zeichen "=", generiert er eine Fehlermeldung, da er den Befehl nicht mit einem Ausdruck identifizieren kann, der weiß, wie die Operation abläuft.
Schreiben Sie dagegen:
QUERY(PtrTable->;PtrField->=True)
oder
QUERY([Table];PtrField->=True)
vermeiden Sie jede Art von Zweideutigkeit.
Konstanten
Erstellen Sie Ihre eigenen 4DK# Ressourcen (Konstanten), stellen Sie sicher, dass Zahlen als Lange Ganzzahl (L) oder Zahl (R) und Zeichenketten als Strings (S) angelegt werden. Jeder andere Typ generiert eine Warnung.
Referenz
Compiler Direktiven, Fehlermeldungen, Richtlinien zur Typisierung, Tipps zur Optimierung.