Variables, Tableaux et Objets

L’une des questions les plus fréquemment posée par les développeurs qui viennent juste d’apprendre que Visual FoxPro ne peut gérer que 65.000 variables est de savoir si cela s’applique aussi aux éléments de tableaux. Aucun doute: NON. Un tableau ne compte que comme une variable, quel que soit le nombre d’éléments qu’il contienne. Le nombre d’éléments étant aussi limité à 65.000 vous pouvez créer jusqu’a 65.000 tableaux de 65.000 éléments. Une masse de données peut être placée en mémoire avec Visual FoxPro. Quoique aucune application performante ne vienne approcher ces limites en raison de la rapidité. La cause de toutes ces limitations est une fois encore la table des noms. En fait, Visual FoxPro sait seulement y gérer des variables, de simples variables. Et le traitement des tableaux, et plus tard des objets a été adapté à ce design. Mais qu’est ce qu’une variable dans Visual FoxPro? Les Variables dans FoxPro peuvent contenir des données de tout type. Cependant, comme Visual FoxPro est lui même écrit en C, les variables de FoxPro, doivent aussi à un moment être stockées dans un format C similaire à celui ci:

typedef struct {

 char              ev_type;
 char              ev_padding;
 short             ev_width;
 unsigned          ev_length;
 long              ev_long;
 double            ev_real;
 CCY               ev_currency;
 MHandle           ev_handle;
 unsigned long     ev_object;

} Value;

Outre le type, il y a l’indication de chaque type de données supporté. Visual FoxPro utilise différents champs en fonction du type de donnée à stocker. La structure explique pourquoi les chaînes peuvent contenir n’importe quels caractères (leur longueur étant stockée séparément) et comment Visual FoxPro gère les décimales dans les valeurs à virgule flottante pour autoriser des différences entre 1.0 et 1.00. La chaîne même, et les objets dont la taille peut varier considérablement ne sont pas stockés directement dans cette structure. Pour accéder aux chaînes, Visual FoxPro utilise ce qui est appelé “memory handle”. Les objets sont identifiés par une valeur 32-bit peu documentée, curieusement il n’est pas fait état des tableaux. Pour chaque nouvelle variable créée par un programme, Visual FoxPro alloue un bloc mémoire avec cette structure Son adresse doit être stockée quelque part, tout comme le nom, qui ne fait pas partie de la structure. La sauvegarde de ces informations est dévolue à la table des noms. Chaque entrée de la table contient, outre le nom et l’étendue, les détails relatifs au type de l’entrée (variable, champ, alias, etc.) et son emplacement dans la mémoire. Cette liste est limitée à 65.000 entrées, et par conséquent détermine le nombre maximum de variables. Un tableau, cependant ne peut être stocké dans une structure unique. Chaque élément en est stocké dans une structure comme une variable. C’est le seul moyen de pouvoir stocker des items de différents types dans le même tableau. Comme dans l’exemple suivant, où tous les éléments du tableau sont définis comme NULL:

LOCAL laArray
laArray = .NULL.

Cette simple entrée est celle utilisée pour passer un tableau par référence. Le tableau lui même, par ailleurs, est la simple liste d’une table qui contient les pointeurs de tous les éléments individuels. La référence au tableau dans la table des noms contient un pointeur vers cette liste. Il n’y a évidemment pas de moyen pour accéder directement à un élément du tableau comme vous pourriez le faire pour une variable. Lorsque l’index de la table des noms (NTI), utilisé par VFP pour identifier de manière unique une entrée de la table des noms, est passé à une fonction en retournant un élément, seul la référence au tableau entier sera renvoyée, une autre fonction recevra cette valeur pour retourner l’élément particulier. Les objets sont stockés de manière similaire. La valeur dans la structure est l’adresse d’un autre nom de table. Pour chaque objet, Visual FoxPro semble créer un nouveau nom de table. Cette voie a probablement été choisie parce que la table des noms gère déjà le nom et l’étendue. Les propriétés dans Visual FoxPro sont en fait des variables gardées dans une place cachée. Plus étonnamment, c’est aussi vrai pour les méthodes, qui sont aussi des variables. Pour cette raison vous ne pouvez créer une classe ayant plus de 65.000 méthodes, propriétés et événements.

Cette conception offre nombre d’avantages, car sinon, les tableaux et les propriétés consommeraient rapidement l’espace disponible de la table des noms. L’inconvénient le plus évident, toutefois, est le passage des paramètres par référence, utilisant le caractère @. Dans ce cas, VFP ne copie des valeurs, comme il le fait d’habitude, mais purement le NTI, l’index de table des noms Il est gentiment demandé à la fonction appelante de mettre le résultat dans la variable numéro x. Cependant un tableau a uniquement un tel index de table des noms. Il n’y a aucune possibilité de spécifier dans quel élément le résultat devrait être écrit. Par conséquent, vous pouvez seulement passer un tableau entier par référence. Dans VFP il est impossible de passer un seul élément par référence. Vous devez copier l’élément dans une variable, passer une référence à cette variable et mettre à jour la valeur dans le tableau. Il en est de même pour les propriétés d’objet. En théorie vous ne pouvez passer une propriété par référence, car c’est une partie intrinsèque de l’objet. Le passage d’une propriété par référence briserait l’encapsulation. La vraie réponse, pourtant, est que la propriété ne possède pas d’entrée dédiée dans la table des noms, et que le passage par référence est donc impossible.

Les propriétés dont la valeur est un tableau sont bien entendu particulièrement affectées par cette conception. Ni les tableaux, ni les propriétés ne peuvent être passées par référence. Vous n’avez donc pas d’autre possibilité que de copier le tableau dans une variable locale, et passer par cette alternative, puis recopier le tableau entier, en utilisant ACOPY() dans les deux cas. Associé avec les méthodes access et assign cette manière de procéder a même plus d’inconvénients que simplement réduire la vitesse d’exécution. Heureusement, VFP 8 apporta la classe collection qui ressemble beaucoup à un tableau, et peut contourner cet obstacle.

L’accès aux variables a été optimisé par VFP. Visual FoxPro traduit à la compilation les noms en des valeurs entières facile à gérer. Les lignes:

LOCAL lcName, lcZIP
? lcName

Sont converties dans le pseudo code suivant lors de la compilation:

LOCAL #1, #2
? #1

Dans le fichier FXP qui en résulte, toutes les variables sont listées à la fin du fichier. A l’intérieur du code compilé, des valeurs 16 bits en indiquant la position sont alors utilisées.

A l’exécution du programme compilé, VFP créé une liste qui assigne un nom dans l’index de la table des noms à chaque variable du code. La longueur du nom de la variable n’est pas pertinent, des noms de variables longs, souvent mieux lisibles, n’ont pas d’effets significatifs sur la vitesse d’exécution. La situation diffère concernant les tableaux, une fonction interne de VFP évalue le paramètre passé par la table des noms pour accéder à l’élément du tableau. Accéder aux éléments d’un tableau est par conséquent toujours plus lent que d’accéder à une variable. Pour compliquer encore les choses, VFP accepte les parenthèses et les crochets, aussi bien pour les tableaux que pour les fonctions. Il n’y a pas distinction claire entre les deux à priori, et VFP doit vérifier si un tableau du même nom existe à chaque appel de fonction. C’est un peu plus difficile pour l’accès aux objets. Une fois encore, les noms de propriétés sont convertis en nombres par l’usage du même algorithme. Cependant objet1.name n’est pas tout à fait la même chose que objet2.name Si VFP rencontre un code tel que :

LOCAL loLabel
loLabel = CREATEOBJECT("Label")
? loLabel.Caption

Il ne lui est pas difficile de déterminer la référence à loLabel de la 3ème ligne. La fonction pour obtenir une valeur de la table des noms retourne une structure qui représente l’intégralité de l’objet. L’étape suivant est beaucoup plus complexe. Les objets contiennent leur propre table de noms. La liste permettant la conversion des noms vers la NTI n’est dès lors d’aucune utilité. VFP doit chercher le nom du code (Caption dans l’exemple) dans la table de l’objet et en charger à chaque fois la structure, cela revient à utiliser le nom réel plutôt que d’utiliser une valeur de l’index et les résultats ne peuvent être traités comme de simples valeurs. L’accès aux propriétés d’un objet est ainsi plus long que l’accès à une variable ou à un élément de tableau.

Cela explique pourquoi WITH…ENDWITH peut notablement améliorer la performance. La structure des valeurs de noms de propriétés pour l’objet est simplement gardée en mémoire, et rend inutile la première partie de la recherche. Cela explique aussi l’intérêt d’utiliser intensivement des variables locales qui en contiendront la valeur, et dont le traitement sera beaucoup plus rapide que celui des propriétés.