Nombre maximum de "property" versions Delphi 2010 et au delà ?
OS : Windows seven. Delphi 2010 et Delphi 7
Résumé : survenue d'une erreur fatale générée par le compilateur DCC sous Delphi 2010.
J'ouvre cette discussion à la fois pour interroger les spécialistes des nouvelles versions Delphi mais également pour donner
une piste potentielle lorsque cette erreur apparaît.
J'aimerais savoir si il y a une limitation seulement dans cette version particulière (D2010) et si elle disparait dans les versions ultérieures.
Après avoir eu cette erreur pour le moins difficile à traiter j'ai réussi à isoler l'élément syntaxique qui l'a provoquée dans mon cas.
L'erreur est provoquée par la déclaration d'un trop grand nombre de "property" dans une classe ce nombre étant précisément égal à 1480.
Il faut savoir qu'avec le compilateur Delphi 7 j'arrive à compiler sans problèmes une classe avec 10000 "property".
Évidement on peut se poser la question de savoir qui peut créer des classes avec 10000 "property" : dans mon application (industrielle) certaines
unités du projet Delphi sont générées automatiquement (parfois on peut faire des choses étonnantes) et ont des dimensions très considérables.
Mes éléments concrets :
Le code (partiel) du projet qui compile sous D7 mais pas sous D2010 (remarque le programme principal n'a pas d'importance)
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
|
//programme principal
library MyLib;
uses
sysutils, myClasse;
var obj:tMyClasse;
begin
obj:=tMyClasse.create;
obj.nombre_0:=5.4;
FreeAndNil(obj);
end.
//unité qui pose problème
unit myClasse;
interface
type
tMyClasse=class
protected
function getVal(index:integer):double;
procedure setVal(index:integer; dbl:double);
public
property nombre_0:double index 0 read getVal write setVal;
property nombre_1:double index 1 read getVal write setVal ;
property nombre_2:double index 2 read getVal write setVal ;
//...etc
property nombre_1480:double index 1480 read getVal write setVal ;
end;
implementation
function tMyClasse.getVal(index:integer):double;
begin
result:=index;
end;
procedure tMyClasse.setVal(index:integer; dbl:double);
begin
exit;
end;
end. |
Le code du programme (console) qui permet de générer autant de "property" que nécessaire
il se lance par la ligne de commande suivante (premier argument : le répertoire pour accueillir le code généré, deuxième argument le nombre de "property"):
genereCodeBugD2010 c:\temp\props 1480
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82
| program genereCodeBugD2010;
{$APPTYPE CONSOLE}
uses
classes,
SysUtils;
procedure generer(const repertoire:string; const nombreProprietes:integer);
var liste:TStringList;
procedure aj(const tab:array of string);
var i:integer;
begin
for I := 0 to high(tab) do
liste.Add(tab[i])
end;
procedure creeProg;
begin
Aj(['library MyLib;']);
Aj(['']);
Aj(['uses']);
Aj([' sysutils,']);
Aj([' myClasse;']);
Aj(['']);
Aj(['var obj:tMyClasse;']);
Aj(['']);
Aj(['begin']);
Aj([' obj:=tMyClasse.create;']);
Aj([' obj.nombre_0:=5.4;']);
Aj([' FreeAndNil(obj);']);
Aj(['end.']);
end;
procedure addProperty(const numPropriete:integer);
begin
Aj([' property nombre_'+intToStr(numPropriete)+':double index '+intToStr(numPropriete)+' read getVal write setVal ;']);
end;
procedure creeUnit();
var i:integer;
begin
Aj(['unit myClasse;']);
Aj(['interface']);
Aj(['']);
Aj(['type ']);
Aj([' tMyClasse=class']);
Aj([' protected']);
Aj([' function getVal(index:integer):double;']);
Aj([' procedure setVal(index:integer; dbl:double);']);
Aj([' public']);
Aj([' property nombre_'+intToStr(0)+':double index 0 read getVal write setVal;']);
for I := 1 to nombreProprietes do addProperty(i);
Aj([' end;']);
Aj(['implementation']);
Aj(['']);
Aj([' function tMyClasse.getVal(index:integer):double;']);
Aj([' begin']);
Aj([' result:=index;']);
Aj([' end;']);
Aj([' procedure tMyClasse.setVal(index:integer; dbl:double);']);
Aj([' begin']);
Aj([' end;']);
Aj(['end.']);
end;
begin
liste:=TStringList.Create;
try
if not directoryExists(repertoire) and not ForceDirectories(repertoire) then exit;
creeProg;
liste.SaveToFile(IncludeTrailingPathDelimiter(repertoire)+'MyLib.dpr');
liste.Clear;
creeUnit;
liste.SaveToFile(IncludeTrailingPathDelimiter(repertoire)+'myClasse.pas');
finally
FreeAndNil(liste);
end;
end;
begin
generer(paramStr(1), StrToIntDef(paramStr(2),10));
end. |
L'erreur renvoyée par le compilateur
[DCC Erreur fatale]F2084 Erreur interne : L3302
Dites moi de quoi vous avez besoin je vous expliquerai comment vous en passer
Citation:
Envoyé par
guillemouze
Je me pose toujours la question, pour quelle raison aurais-tu vraiment besoin d'autant de propriétés ?
Ne pourrais-tu pas utiliser une simple property indexées ?
Code:
property nombre[Index: integer]:double read getVal write setVal ;
Ma question n'est pas tant de savoir comment faire autrement, mais plutôt de comprendre pourquoi D2010 ne compile pas ce que D7 compile. En est-il de même avec Delphi XE7 ?
Il peut sembler que le compilons D2010 plante seulement pour une mauvaise dimension de table interne.
Quid de la qualité du compilateur ?
J'ai été très content de trouver d'où venait l'erreur interne du compilons mais ça m'a pris du temps. J'espère
Seulement que le compilateur ne va pas planter toutes les cinq minutes du fait du non respect de
Règles non écrites par le développeur.
La génération automatique de code est parfois une nécessité
Citation:
Envoyé par P Toth
alors en informatique rien n'est infini; où se situe la limite technique du nombre de propriétés d'une classe Delphi (en fonction de la version du compilateur) ? je n'en sais rien, mais je suis à peu près certain qu'elle est suffisante dans tous les cas - sauf des cas extrêmes comme le tien
En informatique il est souvent très intéressant de générer automatiquement des parties du code d'une application. Cela peut
être nécessité par des questions de performances. Bien souvent le code ainsi généré ne ressemble pas à du code rédigé à la main :
par exemple je génère des unités Delphi "équivalentes" à des classeurs Excel permettant une division par 100 du temps de calcul sachant
que ces unités peuvent contenir jusqu'à 800 000 lignes ! Et là il se trouve que cela ne pose pas de problème au compilateur (D7 ou D2010).
Et oui, parfois, en face d'un jeu de données particulier il est plus intéressant de
- générer un code optimisé pour ce jeu de données
- lancer l'exécutable obtenu à partir de la compilation du code généré
Une autre circonstance est :
- une partie du code doit être écrite par un "non informaticien"
- une partie du code est générée automatiquement afin de faciliter la tâche du "non informaticien"
Qu'ainsi l'ingénieur puisse coder ses équations comme il a l'habitude de le faire, avec les noms de variables dont il a l'habitude
sachant que derrière l'utilisation de ces variables un mécanisme sophistiqué est mis en œuvre (lors du run-time) : cela est
permis par des "property" avec des noms métiers, qui parfois peuvent être en très grand nombre.
Par exemple l'ingénieur refusera d'utiliser fréquemment des expressions du type
TAB[pression]=(TAB[n]*TAB[R]*TAB[temperature])/TAB[volume]
il voudra pouvoir écrire directement :
pression=n*R*temperature/volume
Un compilateur est un outil très complexe dont la réalisation nécessite des méthodes de développement très rigoureuses dont certaines
sont en partie automatisées. Le fait que le compilateur lève une exception au lieu d'annoncer un message du type "code trop complexe, je ne sais pas faire"
m'inquiète un peu, surtout si les versions antérieures du compilateur étaient capables de gérer une complexité au moins égale.
(Note : sous Delphi7 il est possible de faire planter le compilateur en utilisant l'instruction "break;" en dehors d'une boucle).
Bref, existe-t-il une synthèse des limites de complexité gérables par le compilateur DELPHI (à partir de D2010) ?