Session D-SAVE

Speichertechniken in VFP

Alf Borrmann 
denk-modell Software


Inhalt

Dies ist ein Vortrag für Einsteiger in die Visual FoxPro-Programmierung. Es werden die verschiedenen Arten von Variablen erklärt, ein Vergleich mit Properties gemacht, die verschiedenen Arten von Parametern dargestellt und auf mögliche Konflikte z. B. mit Tabellenfeldern hingewiesen. Daneben werden die Möglichkeiten von Konstantendefinitionen und deren Einsatz erklärt sowie die Auswirkung der neuen Typbindung von VFP 7.0 erläutert.

Speicher - was ist das?

Wie in allen Computersystemen wird in Visual FoxPro zwischen "persistentem" und "volatilem" Speicher unterschieden. Das ist nun beides nichts Unanständiges, sondern schlicht die Unterscheidung zwischen Datenspeichern, die länger zur Verfügung stehen, als die Programmlaufzeit ausmacht ("persistent") und dem Speicher, der spätestens bei Beendigung des Programms wieder gelöscht wird ("volatil"). Ersterer wird auch als Festspeicher bezeichnet und besteht aus Sicht von VFP meist aus Dateien im .DBF-Tabellenformat. Die zweite Art Speicher ist aber mindestens genau so interessant, denn hier können während der Laufzeit des Programms alle möglichen Zwischenwerte und Zustände gespeichert werden. Diese Art Speicher wird in den meisten Programmiersprachen als "Variable" bezeichnet. Variable deshalb, weil in einem einmal angelegten Speicherplatz unterschiedliche - also variable - Werte abgelegt werden können.

Variablen in VFP

Wie die meisten anderen Programmiersprachen hat auch Visual FoxPro verschiedene Arten von Variablen. Allen Variablenarten ist gemeinsam, daß sie mit einem Namen versehen werden können. Damit kann über den Namen der Variable auf deren Inhalt zugegriffen werden. Die Zuweisung von Werten zu Variablen geschieht durch ein einfaches =; um einen Wert in einer Variable abzulegen, muß die Anweisung in VFP <Varname> = Wert heißen. Eine Besonderheit von VFP ist, daß in Visual FoxPro der Speicherplatz, den die Variable belegen soll, nicht "deklariert" werden muß. Man muß also - im Gegensatz zu den meisten anderen Sprachen - nicht zuerst eine Speicherstelle anlegen, um einen Wert zu speichern. Gibt man z. B. ein: Test = "ABC" so prüft VFP zunächst, ob ein Speicherbereich mit dem Namen "Test" schon existiert. Wenn das so ist, wird die Buchstabenfolge "ABC" dort abgelegt. Existiert dieser Speicherbereich nicht, legt VFP ihn an, ohne daß der Programmierer davon irgend etwas mitbekommt. Ebenfalls muß die Größe, die eine Variable im Speicher belegt, nicht deklariert werden.

Eine normale Anweisung zum Auslesen eines Wertes könnte ? <Varname> sein; hier wird der Inhalt der Variable <Varname> über den VFP-Befehl "?" ausgelesen und angezeigt. Im gezeigten Beispiel zeigt die Anweisung ?Test also die Buchstaben ABC auf dem Bildschirm an.

Visual FoxPro kann bis zu 65.000 verschiedene Variablen speichern. Allerdings ist die "normale" Anzahl von Variablen, die benötigt werden, wesentlich geringer, so daß es hierfür eine Einstellmöglichkeit gibt. Ohne weitere Anweisungen sieht VFP 1024 Variablen vor. Diese Einstellung kann in der Konfigurationsdatei "Config.FPW" mit der Anweisung MVCount  = <Wert> auf einen Wert zwischen 128 und 65.000 gesetzt werden.

Die Menge Daten, die in den Variablen gespeichert werden kann, ist nur durch den verfügbaren Speicher (hierzu zählt auch der ggf. dynamisch durch Windows belegte Auslagerungsspeicher!) des jeweiligen Rechners begrenzt. Er kann leicht mehr als 1GB betragen.

Die Arten der Variablen unterscheiden sich in zwei Aspekten: anhand der "Datentyps" und anhand des "Sichtbarkeit". Daneben haben die Variablen eine unterschiedliche Lebensdauer, während der sie Speicherplatz belegen.

Datentyp

Visual FoxPro unterscheidet zwischen verschiedenen Datentypen. Datentypen schränken für Programmiersprachen die Anzahl der Regeln ein, mit denen die Datenspeicher behandelt werden können. So ist es in HTML z. B. so, daß dort verwendete Datenspeicher ausschließlich Zeichenketten (engl. character strings bzw. abgekürzt strings) VFP unterscheidet hierbei aber sehr penibel: so kann man z. B. nicht einen Wert vom Datentyp "Datum" mit einem Wert von Datentyp "Character" (also Zeichenkette) multiplizieren. Allerdings stellt VFP sehr viele Funktionen zur Verfügung, um Wandlungen aus einem Datentyp in einen anderen vorzunehmen. 

Wie weiß VFP aber nun, von welchem Datentyp der Wert in einer Variablen ist? In vielen Programmiersprachen muß der Typ explizit angegeben werden, wenn man eine Variable deklariert. Da die Deklaration in VFP aber nicht nötig (bzw. sogar nicht einmal möglich) ist, wird in VFP der Datentyp lediglich durch den Wert selbst, der in der Variablen abgelegt wird, definiert. Da VFP bei der Zuweisung von Werten ebenfalls implizit die Deklaration der Variablen übernimmt (s. o.), bestimmt also die Zuweisung eines Strings, daß der Typ der Variablen vom Typ "Character" ist. Nach den Anweisungen Test1 = "ABC" und Test2 = 123 beinhaltet die Variable Test1 einen Wert von Typ Zeichenkette, die Variable Test2 einen numerischen Wert.

Der Datentyp von Variablen läßt sich in VFP mit Hilfe der Funktion vartype(<Varname> ). Diese Funktion liefert einen Buchstaben zurück, der den Datentyp der Variablen angibt, dabei steht 

Buchstabe

für

C Character (Zeichenkette)
N Numeric (Numerischer Wert; auch float, double, und integer)
Y Currency (Währung)
D Date (Datum)
T DateTime (Datum und Uhrzeit)
L Logical (logisch WAHR oder FALSCH)
O Object (Referenz auf ein Objekt)
U Undefined (undefiniert, also Abfrage eines Variablennamens, der nicht existiert)

 

Durch die implizite Deklaration des Datentyps mit Hilfe der Zuweisung ist es auch möglich, den Datentyp einer Variablen durch Neuzuweisung eines anderen Wertes zu ändern. Die im Beispiel oben genannten Variable Test2 hat also nach der Anweisung Test2 = "DEF" nicht mehr den Datentyp "numeric", sondern den Datentyp "character".

Datentypen in VFP 7.0

Die genannte Technik, daß mit Hilfe

Sichtbarkeit

Variablen sind wie gesagt, Datenspeicher in Programmen. Da aber eine komplette Applikation aus vielen Programmen, Unter- und Teilprogrammen besteht, die nicht immer direkt miteinander zu tun haben, müssen bzw. sollten die Variablen, die in einer Routine benutzt werden, nicht unbedingt in einer anderen Routine sichtbar sein. Hier kann nun mit der Angabe der Sichtbarkeit von Variablen eingegriffen werden. Die Sichtbarkeit (engl. 'visibility' oder 'scope') von Variablen bestimmt, in welchen Programmteilen der belegte Speicherplatz nutzbar ist. Nutzbar heißt hier übrigens, daß die Variablen sowohl lesbar als auch beschreibbar sind. Das Anlegen von Variablen, die in anderen Programmteilen nur lesbar sind, ist nicht möglich.

Zur Unterscheidung der Sichtbarkeit kann man Variablen in VFP mit drei Schlüsselworten deklarieren: public, private und local. Legt man Variablen ohne ausdrückliche Deklaration der Sichtbarkeit wie oben genannt an, so erstellt VFP die Variable als private. Diese Schlüsselworte werden der Nennung des eigentlichen Variablennamens vorangestellt. dabei ist es möglich, gleich mehrere Variablen au einmal zu deklarieren, deren Namen werden dann mit Kommas voneinander getrennt. Beispiele:

Bei der Deklaration der Variable als public oder als local - jedoch nicht bei der Deklaration als private - erhalten diese Variablen direkt einen Inhalt zugewiesen. Dieser steht dann auf .F. (logisch falsch) damit ist gleichzeitig der erste Datentyp der Variable als "L" festgelegt.

Public

Eine Variable als public zu deklarieren führt dazu, daß diese Variable danach im gesamten Programmcode in allen Aufrufstufen sichtbar ist, man spricht hier auch von globalen Variablen. Da eine solche Variable von allen weiteren Programmen verwendet werden kann, kann deren Inhalt und auch deren Datentyp auch in Programmen verändert werden, die dafür eigentlich nicht gedacht sind. Außerdem gibt es bei global vorhandenen Variablen keinen "Eigentümer", also keinen Programmteil, zu dem die Variable direkt gehört. Somit kann an keinem Programmteil entschieden werden, ob die Variable noch benötigt wird und sie wird somit niemals aus dem Speicher gelöscht. Insofern sollte die Verwendung von public-Variablen nur sehr eingeschränkt geschehen.

Private

Wird eine Variable als private deklariert, so kann sie von dem Programm bzw. der Routine genutzt werden, in der sie erzeugt wurde und ist ebenfalls sichtbar in allen Programmen, die von dort aus aufgerufen werden. Nachdem die Routine beendet wird, löscht VFP alle Variablen, die darin als private deklariert wurden, automatisch aus dem Speicher. Die Deklaration von Variablen als private hat ebenso wie die Deklaration als public den Nachteil, daß aufgerufene Programme deren Inhalt verändern können, ohne daß dies in dem aufrufenden Programm gewünscht ist. Insbesondere bei tiefer geschachtelten Programmen kann dies problematisch sein, dadie aufgerufenen Programme einen immer größeren Speicherbereich "nutzen" können.

Local

Die Deklaration von Variablen als local bedeutet, daß die Werte in diesen Variablen nur von dem Anweisungen gesehen und verändert werden können, die im gleichen Programm stehen. Diese Variablen sind nicht sichtbar von Programmen, die aufgerufen wurden. Mit dieser Deklaration kann also verhindert werden, daß (womöglich von fremden Programmierern erstellter) Programmcode Daten ändert, für die dieser nicht zuständig ist. Nach dem Ende des aufgerufenen Programms sind die lokalen Variablen im aufrufenden Programm natürlich wieder ohne Einschränkungen nutzbar. Ähnlich wie die privaten Variablen löscht VFP die als local deklarierten aber nach dem Ende der Prozedur, in der sie erzeugt wurden.

Umdeklaration der Sichtbarkeit

In VFP ist eine Umdeklaration der Sichtbarkeit von Variablen möglich. Dies geht jedoch nur von public nach private und umgekehrt sowie von private nach local und umgekehrt. Eine Variable, die einmal als local oder public deklariert war, kann aber nicht in die andere Form deklariert werden, selbst wenn sie zwischendurch "private" war.

Löschen von Variablen

Neben dem Erzeugen von Variablen hat der Programmierer bei VFP aber auch die Möglichkeit, diese wieder aus dem Speicher zu löschen. Außer dem Löschen von privat oder lokal deklarierten Variablen, die VFP automatisch vornimmt, können beliebig deklarierte Variablen über den Befehl release wieder aus dem Speicher gelöscht werden. Ähnlich wie die Deklaration können dabei mehrere Variable angegeben werden. Der Release-Befehl unterstützt aber auch das Löschen aller Variablen per release all. Sollen dabei auch alle globalen Variablen gelöscht werden, muß hier ein release all extended verwendet werden. Zusätzlich zum Schlüsselwort all kann ein like <Filter> verwendet werden, in dessen Filterausdruck Wildcards ("*" und "?") für Buchstaben verwendet werden können.

Übersicht

  deklariert  Sichtbarkeit  Sichtbar nach Ende 
Programm A 

ruft Programm B auf 

keine  Test1 und Test11 nach Ende von Programm B 
Programm B 

ruft Programm C auf 

kehrt nach A zurück 

publicTest1
privateTest2
local Test3 
alle sichtbar  Test1 
Programm C 

ruft Programm D auf

kehrt nach B zurück 

publicTest11
privateTest22
local Test33 
Test1 und Test11

Test2 und Test22

Test3 nicht sichtbar

Test33 sichtbar 

Test11 
Programm D 

kehrt nach C zurück 

privateTest222
local Test333 
Test1 und Test11

Test2 und Test22

Test3 und Test33 nicht sichtbar

Test333 sichtbar 

keine
 

Übergabe von Daten zwischen Programmen

Per gemeinsam genutzer Variablen

Zur Übergabe von Daten zwischen verschiedenen Programmen könnte man nun die im Unterprogramm verwendeten Daten im aufrufenden Programm als private deklarieren und die Variable, in der der zurückzugebende Wert abgelegt wird, public erzeugen. Wenn man aber aus Gründen der Programmhygiene am besten auf globale und private Variablen verzichtet, wie kann man dann Daten zwischen Programmen austauschen? Schließlich will man die Ergebnisse, die in einem aufgerufenen Programm errechnet wurden, danach im aufrufenden Programm verwenden und außerdem müssen die Berechnungen in dem Unterprogramm ggf. auf Daten zurückgreifen, die das aufrufende Programm bereitstellt.

Als Rückgabe und als Parameter

Die Übergabe eines Wertes aus einem Unterprogramm ist relativ einfach: wie das Ergebnis von FoxPro-Funktionen in Variablen gespeichert werden kann, z. B. bei der Anweisung DatumHeute = date( ), kann ein einzelner Datenwert aus einem aufgerufenen Programm per return-Anweisung zurückgegeben und in einer Variablen gespeichert werden. Dies sieht dann wie folgt aus: 

Nach diesem Durchlauf hat die Variable Test den Wert, der in der Funktion MeinTest berechnet und zurückgegeben wurde. der Vorteil dieser Vorgehensweise ist, daß die Funktion MeinTest nicht wissen muß, wie die Variable heißt, in der der berechnete Wert gespeichert wird. Damit kann sie aus vielen verschiedenen Programmen heraus genutzt werden.

Die Übergabe von Variablen an ein Programm, damit dieses die dort enthaltenen Daten nutzt, kann statt über in beiden Programmen sichtbare Variablen mit sogenannten Parametern oder Argumenten geschehen. Bei der Übergabe von Parametern an ein anderes Programm kann mit den übergebenen Daten gerechnet werden. Dabei besteht - bei richtiger Nutzung - nicht die Gefahr, daß die Werte nach Rückkehr in das aufrufende Programm verändert sind. Außerdem können die Variablen in dem aufgerufenen Programm einen eignen Namen bekommen. Damit sind die jeweiligen Programmierer weniger voneinander und vom Einhalten einer gemeinsamen Vereinbarung zur Benennung der Variablen abhängig.

Im Code muß die Prozedur, die die Parameter erhalten soll, mit einer entsprechenden Programmanweisung darauf vorbereitet werden. Dies sieht dann so aus:


  

Das "parameter"-Statement bedeutet hier, daß beim Aufruf der Funktion MeinTest zwei neue Variablen erzeugt werden, die tcTest1 und tcTest2 heißen. In diesen Variablen speichert VFP die Werte, die von einem aufrufenden Programm übergeben werden. Die Variablen werden von VFP dabei automatisch als "private" deklariert. Sie können im weiteren Verlauf des Programms genutzt werden wie normal "per Hand" deklarierte Variablen. will man die Variablen als "local" deklariert haben, so ist die "parameter"-Statement durch lparameter zu ersetzen. Ebenfalls ist seit der Version VFP 6.0 die Deklaration von lokalen Variablen zu Übernahme von Parametern in der Deklaration der Funktion selbst möglich, die beiden Deklarationen

und

sind dabei in ihrer Funktionalität vollkommen identisch. Die Funktion kann nun in einem aufrufenden Programm mit Test = MeinTest( lcVar1, lcVar2) aufgerufen werden. Dabei werden die Werte, die in lcVar1 und lcVar2 stehen, von VFP an die Funktion MeinTest übergeben.

Übergabearten für Parameter

Die Art und Weise, wie die Variablen übergeben werden, kann dabei unterschiedlich sein: die Variablen können aus lcVar1 und lcVar2 in neue Variablen tcTest1 und tcTest2 kopiert werden oder sie werden nur unter neuem Namen in der gleichen Speicherstelle belassen. Die Art, sie zu kopieren, wird von VFP als "by value" (also Übergabe als Wert), die Art, sie unter anderem Namen aber an der gleichen Stelle im Speicher zu übergeben als "by reference" (als Referenz) bezeichnet. Welche Art VFP verwendet, hängt dabei von verschiedenen Faktoren ab:

  1. der Aufruf: wird die Funktion als Funktion aufgerufen (Test = MeinTest( lcVar1, lcVar2)), werden die Variablen per Kopie ("by value") übergeben, wird die Funktion als Prozedur aufgerufen (do MeinTest with lcVar1, lcVar2), werden die Variablen durch die Übergabe "by reference" weiterverwendet;
  2. die Einstellung von "set udfparms to value| reference" ("UDF" steht für engl.: user defined function, also benutzerdefinierte Funktion, mithin ein selbst geschriebenes Programm): hiermit kann eingestellt werden, daß die Parameter bei Aufruf als Funktion ebenfalls als Referenz übergeben werden sollen. Allerdings betrifft diese Einstellung nur die Aufrufe als Funktion: beim Aufruf als Prozedur werden die Parameter immer per Referenz übergeben;
  3. eine explizite Übergabe: aus Sicht des aufrufenden Programms kann ausdrücklich die Übergabe als "value" bzw. per "reference" angewiesen werden. Damit läßt sich auch die Einstellung von "udfparms" übersteuern. Eine Übergabe als Wert kann mit Hilfe von Klammern um die Variablen, eine Übergabe per Referenz durch Voranstellen eines Klammeraffen erzwungen werden. Diese Einstellung gilt dann immer für genau eine Variable, die beiden Arten können also auch gemischt auftreten. Im Code sähe das dann so aus: do MeinTest with ( lcVar1), @lcVar2 bzw. Test = MeinTest( lcVar1), @lcVar2). In beiden Fällen wird die erste Variable als Wert, die zweite als Referenz übergeben und zwar ohne Berücksichtigung von "set udfparms".

Fehlende Parameter

Enthält ein Programm eine "parameter"- bzw. eine "lparameter"-Anweisung, so werden die damit deklarierten Variablen auf jeden Fall angelegt, egal, ob tatsächlich ein Wert übergeben wurde oder nicht. Werden für einen Parameter keine Werte übergeben, wird dies von VFP ohne weitere Klagen (sprich: Fehlermeldungen) akzeptiert. In diesem Fall enthalten die in der aufgerufenen Funktion deklarierten Variablen einfach den Wert "logisch falsch" (.F.). Ob an eine Funktion Parameter übergeben wurden und wenn ja, wieviele, kann mit den Visual-FoxPro-Funktionen "pcount( )" und parameters( ) abgefragt werden. Diese beiden Funktionen liefern jeweils die Anzahl der zuletzt übergebenen Parameter, im Fall, daß keine Parameter übergeben wurden, also schlicht 0. Bei der Arbeitsweise der beiden Funktionen besteht ein kleiner aber feiner Unterschied: pcount( ) liefert immer die Anzahl der Parameter, die an die aktuelle Funktion geliefert wurden, parameters( ) hingegen die Anzahl Parameter, die zuletzt an ein Programm übergeben wurden. Im Code hätte dies folgende Auswirkungen: 

Achtung: in VFP ist das Auslassen von Parametern möglich, indem man einfach eine Anweisung do MeinTest with , lcVar2 formuliert. Die Funktionen pcount( ) und parameters( ) liefern hier aber trotzdem eine "2" zurück!

Zu viele Parameter

Übergibt man an ein Programm mehr Parameter, als dort deklariert sind, gibt VFP eine Fehlermeldung (Nummer 94: "Must specify additional parameters") aus. Bei Angabe von Parametern, die an ein Programm übergeben werden sollen, wenn dort gar keine Anweisung zur Übernahme von Parametern existiert, wird die Fehlermeldung 1238 ( "No PARAMETER statement is found") ausgegeben.

Arrays

Deklaration und Zugriff

Arrays ( in der deutschen Dokumentation "Datenfelder" genannt) sind eine besondere Art von Variablen: sie können mehrere Werte ("Elemente") beinhalten, die unter einem Namen ansprechbar sind. Zusätzlich zu diesem Namen muß dann eine sogenannten "Subskriptionsangabe" gemacht werden, die angibt, das wievielte Element aus dem Array gemeint ist. Arrays müssen neben der Deklaration der Sichtbarkeit über public, private oder local als eine Angabe zu ihrer Größe haben Die Anzahl der Elemente in einem Array ist auf 65.000 begrenzt. Bei der Deklaration des Arrays verfügen die Befehle von VFP über unterschiedliche Möglichkeiten:

  1. in den Deklarationen "public" und "local" ist das Schlüsselwort "array" erlaubt, das die Deklaration der Arraygröße in einer Zeile erlaubt: public array gaMeinArray[ 10] bzw. local array laMeinArray[ 10] erzeugen jeweils ein Array mit 10 Elementen
  2. ein Array, das als privat deklariert wird, muß in einem zweiten Schritt dimensioniert werden:

Die Arrayelemente erhalten in jedem Fall zunächst den Wert logisch falsch (.F.). Nach der Deklaration kann durch Zugriffe unter Zuhilfenahme der Subskriptnummer ein einzelner Wert gesetzt oder ausgelesen werden:

Es lassen sich auch alle die Werte aller Arrayelemente mit einem Befehl auf einen Wert setzen, indem die Subskriptionsnummer wegelassen wird: laMeinArray = "". Das funktioniert allerdings natürlich nur beim Setzen, ein Auslesen eines Arrays ohne Subskript liefert zwar keinen Fehler, gibt aber immer den Inhalt des ersten Elementes zurück.

Neben den eindimensionalen Arrays, in denen über eine einzelne Subskriptionsangabe auf einzelne Elemente referenziert werden kann, unterstützt VFP zweidimensionale Arrays, allerdings keine drei- oder mehrdimensionalen. Diese zweidimensionalen Arrays kann man sich als Tabelle mit Spalten und Zeilen vorstellen. Bei solchen zweidimensionalen Arrays müssen immer zwei Subskripte angegeben werden: das erste für die Anzahl der Zeilen, das zweite für die Anzahl der Spalten: local array laMeinArray[ 5, 3] erstellt also ein lokales Array mit fünf Zeilen und drei Spalten.

Arrays lassen sich zu jeder Zeit in ihrer Größe verändern, indem einfach eine neue Dimensionierung angegeben wird (dimension laMeinArray[ 6, 4]). Bei einer Verkleinerung des Arrays werden dann einfach die überzähligen Elemente am Ende des Arrays abgeschnitten, bei einer Vergrößerung werden neue Elemente angelegt und erhalten automatisch den Vorgabewert .F..

In einem Array lassen sich in den einzelnen Elementen Werte von jeweils unterschiedlichem Datentyp speichern, ein Array ist also nicht darauf beschränkt, nur Zeichenketten oder nur numerische Werte zu beinhalten, sondern es können alle Datentypen in einem einzigen Array vorkommen. Mit Hilfe dieser Mechanismen kann man nun also temporäre Tabellen im Speicher aufbauen, die innerhalb einer Zeile Strings, numerische Werte und auch Objektreferenzen enthalten. Innerhalb eines solchen Arrays kann nun mit einer einzigen VFP-Funktion, nämlich "ascan( )" nach einzelnen Elementen gesucht werden, ohne daß hier Rücksicht auf den Rdatentyp genommen werden muß.

Übergabe von Arrays als Parameter

Arrays lassen sich auch als Parameter an selbst geschriebene Funktionen weitergeben. Allerdings ist hier eine Besonderheit zu beachten: Arrays können nicht per Value übergeben werden. Da das Array aus vielen Werten besteht, müßte hier ja angegeben werden, welche Werte alle übergeben werden sollen. Eine solche Syntax wird von VFP aber nicht unterstützt Übergibt man einer Funktion im Aufruf nur den Namen des Arrays, also MeinTest( laTest), so interpretiert VFP dies als Übergabe des ersten Elementes aus dem Array. In der korrespondierenden Parameterdeklaration der Funktion "MeinTest" kommt also nur der Wert an, der in laTest[ 1] enthalten ist. Um nun das Array als Ganzes zu übergeben, muß die Übergabe "per Referenz" erfolgen. In dem Aufruf der Funktion ist also dem Arraynamen ein "@" voranzustellen, der Aufruf sähe also so aus: MeinTest( @laTest). Dabei ist nun zu beachten, daß im Parameter der Funktion MeinTest genau die selben (und nicht etwa die gleichen) Werte enthalten sind, die die aufrufende Routine in das Array gesteckt hat. Ändert man nun einen Wert in dem Array, so wirkt sich diese Änderung auch in dem aufrufenden Programm aus.

Funktionen zu Arrays

Arrays werden in VFP in vielen Funktionen unterstützt bzw. genutzt. So liefern viele Befehle und Funktionen ihre Ergebnisse in Arrys zurück, die dabei sogar "on the fly" erzeugt werden können. So können z. B. die Ergebnisse eines SQL Select mit der Klause "into array" direkt in einem Array abgelegt werden. Die Funktion Adir( <ArrayName> ) legt die Informationen der Dateien eines Verzeichnisses mit Dateinamen, -größe, Attributen und Änderungsdatum im übergebenen Array ab und man kann Strukturinformationen einer Tabelle, die Inhalte eines Datensatzes einer Tabelle etc. direkt in Arrays zwischenspeichern. Hinzu kommen viele Funktionen, die das Durchsuchen oder Sortieren von Arrays erlauben oder Funktionen, die einzelne Elemente, Zeilen oder Spalten in der Mitte eines Arrays löschen oder einfügen können.

Objekte und Properties

Objekte in Visual FoxPro bieten neben den Deklarationen von "public", "private" oder "local"-Variablen eine weitere Möglichkeit, den Zugriff auf Speicherstellen einzugrenzen. Dabei kann jedes Objekt selbst in einer Variablen gespeichert werden. Innerhalb des Objektes gibt es nun aber weitere Speicherplätze, ähnlich den Arrayelementen, von denen auch beliebig viele über einen Variablennamen angesprochen werden können. Solche Speicherplätze, die innerhalb eines Objektes liegen, werden als Properties bzw. Eigenschaften bezeichnet. Der Unterschied zwischen Arrayelementen und den Properties ist allerdings, daß die Arrayelemeten nur über eine numerische Referenz innerhalb der Arrayvariablen angesprochen werden können, die Eigenschaften eines Objektes aber eigene Namen haben. Syntax von VFP für den Zugriff auf die Properties ist die Trennung des Propertynamen vom Objektnamen durch einen Punkt. Ist also über den Variablennamen loTestObjekt ein Objekt ansprechbar, das eine Eigenschaft "Name" hat, so kann der Wert dieser Eigenschaft mit der Anweisung ?loTestObjekt.Name erfragt werden. Ebenso ist natürlich das Setzen eines neuen Wertes möglich: loTestObjekt.Name = "Neuer Name". Zu jedem Objekt können beliebig viele Eigenschaften hinzugefügt werden. Interessant hieran ist, daß diese Eigenschaften wiederum die gleichen Merkmale haben, wie die Variablen von VFP. Dies betrifft die möglichen Datentypen und die Namenskonventionen, und sogar das Erstellen eines Properties als Array ist möglich.

Namenskonventionen

Variablen und Properties können mit Namen versehen werden, die maximal 128 Zeichen lang sind. Diese Namen dürfen nur Buchstaben, Ziffern und Unterstriche enthalten, andere Sonderzeichen sind nicht erlaubt. Die Namen müssen mit einem Buchstaben oder einem Unterstrich anfangen. Deutsche Umlaute sind hierbei erlaubt.

Visual FoxPro unterscheidet beim Zugriff auf Variablen ebenso wie bei der Nutzung von eingebauten oder selbst geschriebenen Befehlen oder Funktionen nicht zwischen Groß- und Kleinschreibung. Nach Ablauf der vier Anweisungen


  

existiert also nur eine einzige Variable, die dann das aktuelle Tagesdatum beinhaltet. Es hat sich allerdings bewährt, zur Erhöhung der Lesbarkeit die Variablennamen in gemischter Schreibweise zu schreiben. Dabei wird jeweils der Anfang eines neuen Wortes groß, der Rest klein geschrieben.

Bei der Deklaration von Variablen sollte man sich zudem an die sogenannte "ungarische Notation" halten . Diese Notation sieht vor den eigentlichen Namen der Variablen (z. B. DatumHeute) einen Präfix vor, in dem die Sichtbarkeit der Variablen und deren Datentyp genannt wird. Hierfür werden folgende Buchstaben verwendet:

Sichtbarkeit  Beschreibung  Beispiel 
local  lnZähler 
private (default) pnStatus 
public (global)  gnVorherigerSatz 
Parameter  tnSatznummer

 

Für die Nennung des Typs werden folgende Buchstaben verwendet (vgl. a. Datentyp): 

Typ  Beschreibung  Beispiel 
Array  aMonate 
Character cNachName 
Currency  yAktuellerWert 
Date  dGeburtstag 
Datetime  tLetzteÄnderung 
Double  bWert 
Float  fZinsSatz 
Logical  lStatus 
Numeric   nZähler
Object  oPerson 
Unknown  uRückgabeWert

 

Mögliche Konflikte

Variablen und Tabellenfelder

Für die Benennung von Variablen gelten in VFP die gleichen Vorschriften, wie für die Benennung von Feldern einer Tabelle. Insofern läßt sich innerhalb der Codezeile lcTest = Name nicht unterscheiden, ob der Inhalt der Variablen lcTest nachher dem Inhalt der Variablen Name entspricht oder ob hier der Inhalt des Feldes NAME aus einer Tabelle gelesen wurde. Da auch VFP dies in diesem Beispiel nicht unterscheiden kann, geht das Programm hier davon aus, daß mit "Name" der Inhalt eines Tabellenfeldes gemeint war, wenn die Tabelle in aktuellen Arbeitsbereich ein solches Feld enthält. Dabei ist VFP völlig egal, der Nennung von "Name" kein Alias vorangestellt ist.

Dieser Vorrang für die Datenfelder kann nur umgangen werden, indem einer Variablen, so sie denn mit "Name" gemeint sein soll, ein "m." vorangestellt wird. Da der Buchstabe "M" nicht als Alias für eine Tabelle erlaubt ist, ist damit die Eindeutigkeit für VFP wiederhergestellt: lcTest = m.Name. Allerdings ist es hier erstaunlicherweise so, daß VFP die Voranstellung des "m." mit einer (wenn auch nur geringfügig) längeren Ausführungszeit quittiert. Es kann also zu Erreichung einer maximalen Performance sinnvoll sein, die Unterscheidung von Feldern und Variablen nur anhand der verschiedenen Namenskonventionen zu machen. Schließlich dürfte eine Variable nach den oben genannten Konventionen eigentlich nur z. B. "lcName" heißen, Da aber die Deklaration von "local" bzw. "private" oder "public" für Tabellenfelder nicht sinnvoll ist, kann das entsprechende Feld einer Tabelle dann nur "cName" heißen, wodurch eine Verwechslung ausgeschlossen ist.

Vergleiche liefern falsche Ergebnisse

Je nach Einstellung von "SET EXACT" führt VFP Vergleiche von Variablen unterschiedlich aus. In folgender Codesequenz liefert der Vergleich zum Schluß tatsächlich ein ".T."! 


  

Woran liegt das nun wieder? Die beiden Strings sind doch nun definitiv nicht gleich. Zusätzlich verworren wird das Ganze, wenn man den Ausdruck umdreht. Die Frage


  

liefert wiederum ein ".F."! Hier muß man schlicht wissen, daß VFP bei der Einstellung "OFF" von "EXACT" die beiden Strings nur so lange vergleicht, bis das Ende des zweiten Strings erreicht wurde. Wurde bis hierher kein Unterschied festgestellt, sind die beiden Strings für VFP gleich. Will man sicher sein, daß VFP wirklich darauf untersucht, daß beide Strings hundertprozentig gleich sind, so ist die Anweisung "= =" zu verwenden. Die liefert ohne Rücksicht auf die Einstellung von "set exact" das Ergebnis eines vollständigen Vergleichs, nämlich in der letzten Zeile von:


  

tatsächlich ein ".F.".

Das gleiche Verhalten von VFP finden wir, wenn wir innerhalb von Feldern in einer Tabelle suchen. In einer Tabelle sei ein Feld mit Namen "Name" und der Länge 10 enthalten. Dazu ist ein Index auf das Feld "Name" aktiv:

 dann liefert die folgende Sequenz ein ".T.", obwohl der String in lcTest1 um 7 Zeichen kürzer ist, als der Inhalt des Datenfeldes: lcTest1 = "ABC" ?seek( lcTest1)

Dies gilt übrigens auch, wenn "set exact" auf "ON" steht.

Konstanten

Die Speicherung von Daten in Variablen hat neben dem Anteil, daß hier variable Werte in den Speicherstellen abgespeichert werden können, den Vorteil, daß diese Werte über einen speziellen Namen angesprochen werden können. Die Verwendung von solchen "sprechenden" Namen ist auch für Daten wünschbar, die sich nicht während der Laufzeit eines Programmes verändern. Solche Daten können als sogenannte Konstanten definiert werden. Wofür aber nun solche Konstanten definieren, schließlich kann man Daten, die sich nicht mehr ändern ja auch direkt in den Code schreiben? Ein Vorteil von Konstanten ist, daß ihnen Namen gegeben werden können. Besonders praktisch ist dies, wenn in einem Programm mehrspaltige Arrays (s.d.) verwendet werden sollen. Innerhalb dieser Arrays müssen die Spalten ja immer über Nummern angesprochen werden, z. B. laMeinArray[ 6, 4]. Bei dieser Programmierung muß man sich innerhalb des Programms immer daran erinnern, was nun in Spalte 4 des Arrays steht, aber woher kann man dies wissen? Bliebe nur, alle Zugriffe auf das Array mit Kommentaren zu versehen, oder eben Konstanten zu verwenden. Angenommen, wir haben in dem Array laMeinArray mit Hilfe der Funktion adir( ) die Informationen eines Directories abgelegt. Dann stünde in der vierten Spalte des Arrays die Zeit der letzten Speicherung der Datei. Um sich nicht immer daran erinnern zu müssen, daß die Zeit nicht in der fünften Spalte steht, kann man eine Konstante mit dem Namen k_nSpeicherzeit anlegen und dieser den Wert 4 geben. Damit sähe die genannte Anweisung dann so aus: laMeinArray[ 6, k_nSpeicherzeit]. Das ist schon einigermaßen sprechend, und braucht nicht mehr kommentiert zu werden.

Wie funktionieren nun Konstanten? Innerhalb eines Programmes können zur Zuweisung von Werten zu solchen Namen beliebige "defines" liegen. Diese Definitionen haben folgendes Format: #define k_nSpeicherzeit 4. Trifft der Compiler nun auf eine solche Anweisung, speichert er diese Zuweisung intern, ersetzt in den folgenden Codezeilen den Namen mit dem zugewiesenen Wert und compiliert diesen. Für das compilierte Programm macht diese Zuweisung also keine Unterschied und kostet demnach auch keine Laufzeit. Vor allem bei der Definition von numerischen Konstanten ergibt sich ein spezieller Vorteil, wenn sich die Struktur eines Arrays doch einmal ändert, also eine Spalte hinzugefügt wird und sich alle anderen nach hinten verschieben: hier genügt eine einfache Anpassung der Wertzuweisungen der Konstanten und ein anschließendes Neucompilieren, ohne daß man manuelle Änderungen an den Codestellen machen muß. Aber auch bei größeren Änderungen, für die man die zugehörigen Codestellen suchen muß, ist es besser, zum Ändern aller betroffener Codestellen nach einem aussagekräftigen Namen zu suchen und nicht nach einer einzelnen Ziffer, denn damit wird die Anzahl der gefundenen Stellen drastisch eingeschränkt.

Es lassen sich beliebig viele Konstanten definieren. Diese Definitionen lassen sich in Dateien zusammenfassen, die normalerweise mit der Endung ".H" (für ("Header") versehen werden. Diese Dateien und damit alle enthaltenen Konstantendefinitionen können dann per "#include"-Anweisung in eine Programmdatei eingebunden werden. Eine solche Datei wird mit VFP bereits mitgeliefert. In dieser sind bereits einige Konstanten für Arrays oder andere VFP-Funktionen definiert. Die Progrmme werden mit Einsatz dieser Konstanten erheblich lesbarer, denn wissen Sie, was die Funktion messagebox( "Nachricht", 52) ausgibt? Mit Hilfe von Konstanten ergibt sich hier ein messagebox( "Nachricht", MB_YESNO + MB_ICONEXCLAMATION), also eine Nachricht mit Ja- und Nein-Knopf und einem Ausrufezeichen als Icon und das ist doch schon viel lesbarer oder?

 

In diesem Sinne: 

Referenzen

Jim Booth: "A Day in the Life of a Variable", FoxTalk July 1999

Online-Hilfe zu Visual FoxPro