Logo

Marco Cantù's
Essential Pascal

Kapitel 10
Varianten

Damit eine volle OLE-Unterstützung möglich ist, umfasst die 32-bit Version von Delphi den Datentyp Variant. Hier möchte ich diesen Datentyp aber aus einer allgemeineren Perspektive behandeln. Tatsächlich hat der Datentyp Variant einen sehr starken Einfluss auf die gesamte Sprache, der weit über die OLE-Programmierung hinausgeht und auch die Delphi Komponentenbibliothek benutzt sie oft in einer Weise, die nicht mit der OLE-Porgrammierung in Verbindung steht.

Varianten haben keinen Datentyp

Im allgemeinen können Sie Varianten verwenden, um beliebige Datentypen zu speichern, zahlreiche Operationen auszuführen und Typkonvertierungen durchzuführen. Beachten Sie, dass dieses jedoch dem allgemeinen Ansatz der Sprache Pascal und einem guten Programmierstil entgegen läuft. Eine Variante wird zur Laufzeit Type-geprüft und berechnet. Der Compiler warnt Sie nicht über mögliche Fehler im Quellcode, welche nur durch umfangreiche Prüfungen entdeckt werden können. Im allgemeinen können Sie die Codeteile, die Varianten verwenden, als interpretierten Code betrachten, da genau wie bei interpretiertem Code viele Operationen erst zur Laufzeit augelöst werden können. Dieser Umstand beeinflusst insbesondere die Ausführungsgeschwindigkeit des Codes.

Nun, da ich Sie vor dem Gebrauch von Variant Datentypen gewarnt habe, ist es Zeit, zu sehen was man mit ihnen anfangen kann. Grundsätzlich können Sie, nachdem Sie eine Variant-Variable wie folgt deklariert haben:

var

  V:  Variant;

die unterschiedlichsten Werte zuweisen:

V := 10;
V := 'Hallo, Freunde';
V := 45.55;

Sobald Sie einen Variant-Wert haben, können Sie ihn an beliebige kompatible oder inkompatible Datentypen zuweisen. Wenn Sie einen Wert an einen inkompatiblen Datentyp zuweisen, so führt Delphi, soweit das möglich ist, eine Konvertierung durch. Andernfalls wird ein Laufzeitfehler ausgegeben. Intern speichert eine Variante Typinformationen zusammen mit den Daten und erlaubt damit eine Anzahl von Laufzeitoperationen; diese Operationen können praktisch sein, sie sind aber sowohl langsam als auch unsicher.

Betrachten Sie das folgende Beispiel (genannt VariTest), das eine Erweiterung des obigen Codes ist. Ich platzierte drei Eingabefelder auf einem neuen Formular, fügte zwei Schalter hinzu und schrieb dann den folgenden Code für das OnClick-Ereignis des ersten Schalters:

procedure TForm1.Button1Click(Sender: TObject);
var
  V: Variant;
begin
  V := 10;
  Edit1.Text := V;
  V := 'Hallo, Freunde';
  Edit2.Text := V;
  V := 45.55;
  Edit3.Text := V;
end;

Lustig, nicht war? Neben der Zuweisung einer Variante, die eine Zeichenkette enthält, an die Text-Eigenschaft eines Eingabefeldes, können Sie an Text auch eine Variante zuweisen, die eine Ganzzahl oder eine Gleitkommazahl enthält. Wie Sie in Abbildung 10.1 sehen können, arbeiten alle drei Möglichkeiten.

Abbildung 10.1: Die Ausgabe des VariTest-Beispiels, nachdem der Schalter Assign betätigt worden ist.

Sie können Varianten sogar verwenden, um Werte zu berechnen, wie Sie im folgenden Code sehen können, der mit dem zweiten Schalter in Verbindung steht:

procedure TForm1.Button2Click(Sender: TObject);
var
  V: Variant;
  N: Integer;
begin
  V := Edit1.Text;
  N := Integer(V) * 2;
  V := N;
  Edit1.Text := V;
end;

Diese Art von Code zu schrieben ist riskant, um es vorsichtig auszudrücken. Wenn das erste Eingabefeld eine Zahl beinhaltet, so arbeitet alles korrekt. Wenn nicht, so wird eine Exception ausgelöst. Es soll noch einmal betont werden, dass man ohne einen triftigen Grund keinen derartigen Code schreiben sollte, sondern besser auf traditionelle Pascal-Datentypen und deren Ansatz zur Typprüfung zurückgreift. In Delphi und in der VCL (Visuelle Komponentenbibliothek), werden Varianten vorrangig für die Unterstützung von OLE und für den Zugriff auf Datenbankfelder verwendet.

Varianten im Detail

Delphi besitzt einen variablen Record-Typ TVarData, der das gleiche Speicherlayout wie ein Variant-Typ besitzt. Sie können diesen Record-Typ verwenden, um auf den aktuellen Typ einer Variante zuzugreifen. Die TVarData- Struktur umfasst den Typ der Variante, erkennbar über VType, einige reservierte Felder und den tatsächlichen Wert.

Die möglichen Werte des VType- Feldes entsprechen den Datenarten, die Sie bei der OLE-Automatisierung benutzen können und daher oft als OLE-Typen oder Variant-Typen bezeichnet werden. Hier folgt eine komplette alphabetische Liste der vorhandenen Variant-Typen:

Eine genaue Beschreibung dieser Variant-Typen finden Sie in der Delphi Online-Hilfe unter dem Punkt Varianten | VarType (Funktion).

Es existieren auch viele Funktionen für die Arbeit mit Varianten, die Sie verwenden können, um spezifische Typkonvertierungen durchzuführen oder um Informationen über den aktuellen Typ einer Variante zu ermitteln (vergl. dazu z.B. die Funktion VarType). Die meisten dieser Typkonvertierungen und Zuweisungsfunktionen werden automatisch verwendet, wenn Sie Ausdrücke mit Varianten schreiben. Andere Variant-Hilfsfunktionen (vergl. dazu das Thema Varianten in der Online-Hilfe), betreffen die Bearbeitung von Variant-Arrays.

Varianten sind langsam!

Programmcode, der Variant-Typen verwendet, ist langsam und das nicht nur, wenn eine Typumwandlung erfolgt, sondern auch dann, wenn zwei Variant-Variablen addiert werden, die jeweils einen Integer-Wert enthalten. Er ist fast genauso langsam wie der interpretierte Code von Visual Basic! Um die Geschwindigkeit eines Algorithmus der auf der Verwendung von Variants basiert, mit dem gleichen Code, basierend auf normalen Integer-Variablen, zu vergleichen, können Sie das folgende VSpeed-Beispiel betrachten.

Dieses Programm läuft in einer Schleife, ermittelt deren Geschwindigkeit und zeigt den aktuellen Status in einem Fortschrittsbalken an. Hier folgt die erste von zwei sehr ähnlich aufgebauten Schleifen, basierend auf Integer-Variablen und auf Varianten:

procedure TForm1.Button1Click(Sender: TObject);
var
  time1, time2: TDateTime;
  n1, n2: Variant;
begin
  time1 := Now;
  n1 := 0;
  n2 := 0;
  ProgressBar1.Position := 0;
  while n1 < 5000000 do
  begin
    n2 := n2 + n1;
    Inc (n1);
    if (n1 mod 50000) = 0 then
    begin
      ProgressBar1.Position := n1 div 50000;
      Application.ProcessMessages;
    end;
  end;
  // wir müssen das Ergebnis benutzen
  Total := n2;
  time2 := Now;
  Label1.Caption := FormatDateTime (
    'n:ss', Time2-Time1) + ' Sekunden';
end;

Der Code zur Zeitmessung verdient einen näheren Blick, da er leicht an jede beliebige Art von Performance-Test angepasst werden kann. Wie Sie sehen können, verwendet das Programm die Funktion Now, um die aktuelle Zeit zu ermitteln sowie die Funktion FormatDateTime, um die Zeitdifferenz auszugeben. Hierbei werden nur die Minuten ("n") und die Sekunden ("ss") vom Format-String ausgewertet. Alternativ können Sie auch die Windows-API Funktion GetTickCount verwenden, welche eine sehr präzise Angabe über die vergangenen Millisekunden seit dem Start des Betriebssystems liefert.

In diesem Beispiel ist jedoch der Geschwindigkeitsunterschied so groß, dass Sie ihn auch ohne präzise Zeitmessung erkennen können. Wie dem auch sei, in Abbildung 10.2 können Sie die Ergebnisse für meinen eigenen Computer sehen. Die tatsächlichen Werte sind abhängig vom Computer, auf dem das Programm ausgeführt wird, aber das Verhältnis ändert sich dadurch nur unwesentlich.

Abbildung 10.2: Der Geschwindigkeitsunterschied des selben Algorithmus unter Verwendung von Integer- und Variant-Typen, wie er durch das VSpeed Beispiel ausgegeben wird (die ermittelten Zeitwerte variieren in Abhängigkeit des verwendeten Computers).

Zusammenfassung

Varianten unterscheiden sich so fundamental von traditionellen Pascal-Datentypen, dass ich beschlossen habe, sie in diesem kurzen eigenen Kapitel darzustellen. Obwohl ihr Schwerpunkt bei der OLE-Programmierung liegt, können sie nützlich sein, um Programme auf die Schnelle (quick and dirty) zu schreiben, ohne sich dabei Gedanken um Datentypen machen zu müssen. Wie wir aber gesehen haben, beeinträchtigen Varianten die Performance erheblich.

Nachdem wir nun die meissten Sprachelemente behandelt haben, lassen Sie mich noch auf die allgemeine Struktur eines Programms und dessen Modularisierung durch Units eingehen

.

Nächstes Kapitel: Programme und Units

© Copyright Marco Cantù, Wintech Italia Srl 1995-2000
© Copyright der deutschen Übersetzung Immo Wache, 2000