Logo

Marco Cantù
Essential Pascal


Tradotto dall'inglese da: Paolo Rossi

Capitolo 10
Il tipo variant

Per avere un pieno supporto OLE, le versioni a 32 bit di Delphi includono il tipo di dato Variant. Qui voglio discutere questo tipo di dato da una prospettiva generale. Il tipo Variant, di fatto, ha un effetto esteso all'intero linguaggio e nella libreria dei componenti di Delphi viene usato per cose non necessariamente relazionate alla programmazione OLE.

I Variant non hanno Tipo

In generale, si possono usare i Variant per memorizzare qualsiasi tipo di dato e compiere diverse operazioni e conversioni di tipo. Da notare che questo va contro l'approccio generale del linguaggio Pascal e va contro le regole di buona programmazione. Un tipo Variant e' controlalto e calcolato a run-time. Il compilatore non avvisera' di possibili errori nel codice, i quali potranno essere scoperti solo dopo un ciclo pesante di testing. Nel complesso, si possono considerare le porzioni di codice che usano i variant come codice interpretato, visto che, come il codice interpretato, le operazioni non possono essere risolte che a run-time. Questo influenza in particolare la velocita' di esecuzione del codice.

Adesso che ho avvertito dei pericoli nell'uso del tipo Variant, e' tempo di guardare come si possono usare. Basilarmente, una volta dichiarato una variabile variant come nel seguente codice:

var
  V: Variant;

si possono assegnare ad essa valori di diversi tipi:

V := 10;
V := 'Hello, World';
V := 45.55;

Una volta che si ha il valore del variant, lo si puo' copiare in tipo compatibile o incompatibile. Se si assegna un valore ad un tipo non compatibile, Delphi se possibile effettuera' una conversione. Altrimenti verra' generato un errore a run-time. Di fatto, un variant immagazzina le informazioni sul tipo assieme al dato, permettendo cosi' diverse operazioni a run-time, queste operazioni possono essere pratiche ma sono lente e pericolose.

Si consideri il seguente esempio (chiamato VariTest), che e' un'estensione del codice visto sopra. Ci sono tre editbox su un nuovo form, alcuni pulsanti e il seguente codice nell'evento OnClick del primo pulsante:

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

Buffo vero? Oltre ad assegnare un variant che una stringa alla proprieta' Text di un componente edit, si puo' assegnare alla proprieta' Text un variant che contiene un intero o un valore reale. Come si puo' vedere in Figura 10.1, funziona tutto.

Figure 10.1: L'output dell'esempio VariTest dopo che il pulsante Assign e' stato premuto.

Cosa ancora peggiore, si possono usare i variant per calcolare valori, come si puo' vedere nel codice relativo al secondo pulsante:

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

Scrivere questo tipo di codice e' a dir poco rischioso. Se il primo edit box contiene un numero, tutto ok. Se non contiene un numero e' generata un'eccezione. Di nuovo, si puo' scrivere codice similare, ma senza una ragione per farlo, non si dovrebbe usare il tipo Variant, invece bisogna cercare di usare il piu' possibile i tipi di dato tradizionali del Pascal. In Delphi e nella VCL (Visual Component Library), i variant sono usati per il supporto OLE e per accedere ai campi di database.

Approfondimento sui Variant

Delphi include un tipo di record variant, TVarData, il quale ha la stesso schema di memoria del tipo Variant. Si puo' usare questo tipo per accedere al tipo reale di un variant. La struttura TVarData include il tipo del Variant, indicato come VType, alcuni campi riservati e il valore del Variant.

I possibili valori del campo VType, corrispondono ai tipi di dato che si possono usare nell'automazione OLE e sono spesso chiamati tipi OLE o tipi variant. Ecco un elenco (in ordine alfabetico) dei tipi variant disponibili:

Si puo' trovare la descrizione di questi tipi nell'argomento Variant nell'help online di Delphi.

Ci sono anche diverse funzioni per operare sui variant che si possono usare per specifiche conversioni di tipo o per richiedere informazioni riguardo il tipo di un variant (ad esempio la funzione VarType). La maggior parte di queste funzioni di conversione sono in realta' chiamate automaticamente quando si scrivono espressioni che usano i variant. Le altre routine di supporto per i variant (vedere l'argomento Variant Support Routines nel file di help) in realta' operano sui variant array.

I Variant sono lenti!

Il codice che usa il tipo variant e' lento, non solo quando si convertono i tipi, ma anche quando si sommano due variant che contengono entrambi un valore intero. Piu' o meno il codice e' lento come il codice interpretato di Visual Basic! Per raffrontare la velocita' di un algoritmo basato sui variant e di uno basato sugli interi, si puo' guardare l'esempio VSpeed.

Questo programma esegue un ciclo, calcola la velocita' di esecuzione e mostra lo stato in una progress bar. Qui, e' il primo dei due cicli davvero simili, basati sugli interi e variant:

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;
  // we must use the result
  Total := n2;
  time2 := Now;
  Label1.Caption := FormatDateTime (
    'n:ss', Time2-Time1) + ' seconds';
end;

Vale la pena di guardare il codice della temporizzazione, visto che e' possibile adattarlo ad ogni tipo di test delle prestazioni. Come si puo' vedere, il programma usa la funzione Now per ottenere l'ora corrente e la funzione FormatDateTime per scrivere la differenza, richiedendo solo i minuti ("n") e i secondi ("ss") nella stringa di formato. Come alternativa, si puo' usare la funzione API di Windows GetTickCount, che ritorna con un'alta precisione in numero di millisecondi trascorsi da quando il sistema operativo e' partito.

In questo esempio la differenza di velocita' e' in realta' cosi grande che si nota anche senza un controllo preciso. Ad ogni modo, si puo' vedere il risultato in Figura 10.2. I valori reali dipendono dal computer usato per eseguire il programma, ma la proporzione non cambiera' di molto.

Figura 10.2: Le differenti velocita' di esecuzione dello stesso algoritmo, basato su integer e variant (i tempi variano a seconda del computer usato), come sono mostrati dall'esempio VSpeed.

Conclusioni

I Variant sono cosi' diversi dai tipi di dato tradizionali del Pascal, che ho deciso di descriverli separatamente in questo breve capitolo. Sebbene il loro ruolo sia nella programmazione OLE, essi possono essere pratici per scrivere programmi "quick and dirty" senza preoccuparsi dei tipi di dato. Come si e' visto questo pero' penalizza di molto le prestazioni.

Dopo aver discusso delle principali caratteristiche del linguaggio, si prendera' in esame la struttura generale di un programma e la modularizzazione offerta dalle unit.

Prossimo Capitolo: Programmi e unit

© Copyright Marco Cantù, Wintech Italia Srl 1995-2000