Logo

Marco Cantù

L'essentiel sur Pascal

Traduit de l'anglais par Iannis Papageorgiadis ipapag@village.uunet.be

Chapitre 10
Les types Variant

Pour fournir un support OLE complet, la version 32 bits de Delphi comporte le type de données Variant. Nous traiterons ici ce type de données d'un point de vue général. Le type Variant est, en fait, diffus dans tout le langage et la bibliothèque des composants Delphi l'utilise dans des situations qui n'ont rien à voir avec la programmation OLE.

Les variants n'ont pas de type

En général, on utilise des variants pour stocker n'importe quel type de données et pour effectuer de nombreuses opérations et conversions de type. Ce qui, il faut le noter, est contraire à l'approche générale du langage Pascal et aux pratiques correctes de programmation. Un variant est un type vérifié et calculé à l'exécution. Le compilateur ne signalera pas les erreurs possibles dans le code; elles ne peuvent être détectées que par un contrôle étendu. Globalement, on peut considérer les portions de code qui utilisent des variants comme du code interprété, puisque, comme avec du code interprété, nombre d'opérations ne peuvent être résolues avant l'exécution. Ceci affecte surtout la vitesse du code.

Après cette mise en garde quant à l'utilisation du type Variant, examinons ce que ce type peut faire. Fondamentalement, une fois que l'on a déclaré une variable de type Variant comme la suivante :

var

  V: Variant;
on peut lui affecter des valeurs de types différents :
V := 10;

V := 'Hello, World';

V := 45.55;
Une fois que l'on dispose de la valeur variant, on peut la copier dans n'importe quel autre type de données compatible ou non. Si on assigne une valeur à un type de données incompatible, Delphi effectue une conversion si cela est possible. Sinon il déclenche une erreur d'exécution. En fait, les variants stockent le type d'information avec la donnée et permettent un certain nombre d'opérations à l'exécution; ces opérations peuvent être pratiques mais sont lentes et peu sûres.

Considérons l'exemple suivant (appelé VariTest), qui est une extension du code précédent. Sur une nouvelle fiche, nous avons placé trois boîtes de saisie (Edit) et deux boutons, et nous avons écrit le code suivant pour l'événement OnClick du premier bouton :

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;
Bizarre, n'est-ce pas? En plus d'assigner un variant contenant une chaîne à la propriété Text d'un composant TEdit, on peut lui assigner un variant contenant un nombre entier ou un nombre à virgule flottante. Tout cela fonctionne, comme on le voit à la figure 10.1.
 
Figure 10.1 : L'affichage de l'exemple VariTest après le clic sur le bouton Assigner.
 

Pire encore, on peut utiliser les variants pour calculer des valeurs, comme on peut le voir dans le code relatif au second bouton:

procedure TForm1.Button2Click(Sender: TObject);

var

  V: Variant;

  N: Integer;

begin

  V := Edit1.Text;

  N := Integer(V) * 2;

  V := N;

  Edit1.Text := V;

end;
Écrire ce genre de code est risqué, c'est le moins qu'on puisse dire. Si la première boîte d'édition (TEdit) contient un nombre, tout fonctionne. Sinon, une exception est levée. De nouveau, on peut écrire un code semblable mais, sans raison valable pour le faire, on ne devrait pas utiliser le type Variant; mieux vaut rester fidèle aux types de données Pascal traditionnels et à l'approche de vérification de type. Dans Delphi et dans la VCL (Bibliothèque des composants visuels), les variants sont fondamentalement utilisés pour le support d'OLE et pour l'accès aux champs des bases de données.

Les Variants en profondeur

Delphi comprend un type enregistrement variable, TVarData, qui a la même disposition en mémoire que le type Variant. On peut l'utiliser pour accéder au type réel d'un variant. La structure TVarData contient le type du variant, nommé VType, quelques champs réservés, ainsi que la valeur réelle.

Les valeurs possibles du champ VType correspondent aux types de données qu'on peut utiliser dans OLE Automation, souvent appelés types OLE ou types Variant. Voici une liste alphabétique complète des types variants disponibles :

On trouvera des descriptions de ces types dans la rubrique VarType de l'aide Delphi.

Il existe aussi de nombreuses fonctions qui travaillent sur des variants; on les utilise pour effectuer des conversions spécifiques ou pour obtenir des informations à propos du type d'un variant (p.ex. la fonction VarType). La plupart de ces fonctions de conversion de type et d'assignation sont en fait appelées automatiquement lorsqu'on écrit des expressions utilisant des variants. D'autres routines de support de variants (voir la rubrique Routines de support de variants de l'aide Delphi) travaillent en fait sur des tableaux de variants.

Les variants sont lents!

Le code qui utilise le type Variant est lent, pas uniquement lors de la conversion des types de données, mais également lorsqu'on additionne deux valeurs variant contenant chacune un entier. Il est presque aussi lent que le code interprété du Visual Basic! Pour comparer la vitesse d'un algorithme basé sur des variants à celle du même code basé sur des Integer, voyons l'exemple VSpeed.

Ce programme fait tourner une boucle, il mesure sa vitesse et en affiche l'état dans une barre de progression. Voici la première de deux boucles très semblables, basées sur des Integer et sur des variants :

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;

  // nous devons utiliser le résultat

  Total := n2;

  time2 := Now;

  Label1.Caption := FormatDateTime (

    'n:ss', Time2-Time1) + ' secondes';

end;
Le code de chronométrage vaut la peine d'être examiné, parce qu'il est facilement adaptable à tout type de test de performances. Comme on le voit, le programme utilise la fonction Now pour obtenir l'heure courante, et la fonction FormatDateTime pour afficher la différence de temps, en indiquant uniquement les minutes ("n") et les secondes ("ss") dans la chaîne de format. On peut également utiliser la fonction API Windows GetTickCount, qui retourne une  indication très précise des milli-secondes écoulées depuis le démarrage du système d'exploitation.

Dans cet exemple, la différence de vitesse est tellement grande qu'on la remarquera même sans un chronométrage précis. Voici, en tout cas, à la figure 10.2, les résultats de notre ordinateur. Les valeurs réelles dépendent de l'ordinateur utilisé pour faire tourner ce programme, mais la proportion ne devrait pas être fort différente.
 

Figure 10.2 : Les différentes vitesses du même algorithme basé sur des Integer et sur des variants (le chronométrage réel varie en fonction de l'ordinateur), comme les affiche l'exemple VSpeed.
 

Conclusion

Les variants sont si différents des types de données Pascal traditionnels que nous avons décidé de les traiter à part dans ce bref chapitre. Quoique leur rôle soit prévu pour la programmation OLE, ils peuvent se révéler pratiques pour écrire des programmes à la va vite sans même devoir réfléchir aux types de données. Ceci, on l'a vu, affecte sérieusement les performances.

Après avoir traité de la plupart des fonctionnalités du langage, voyons la structure générale d'un programme et la modularisation offerte par les unités.

Chapitre suivant : Programme et unités

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