Déclaration de variable inline
Dans 10.3, le langage Delphi permet une plus grande souplesse dans la déclaration des variables locales. Jusqu'à maintenant, en conformité avec les règles du langage Pascal, toutes les déclarations de variables devaient être effectuées dans un bloc var qui était écrit avant le début d'une fonction, d'une procédure ou d'une méthode.
procedure Test;
var
I: Integer;
begin
I := 22;
ShowMessage (I.ToString);
end;
La nouvelle syntaxe de déclaration des variables inline vous permet de déclarer la variable directement dans un bloc de code (tout en permettant d'utiliser plusieurs symboles).
procedure Test;
begin
var I: Integer;
I := 22;
ShowMessage (I.ToString);
end;
procedure Test2;
begin
var I, K: Integer;
I := 22;
K := I + 10;
ShowMessage (K.ToString);
end;
Même si c'est un changement limité, il convient de signaler quelques effets secondaires. La déclaration et l'initialisation peuvent être effectuées dans une seule instruction. Vous pouvez déclarer des variables dans un bloc de code complexe avec une portée limitée (la variable est uniquement visible depuis l'emplacement de sa déclaration et il n'est pas nécessaire qu'elle soit déclarée et non initialisée pour la portion de code).
Sommaire
Portée des variables inline
Il existe un troisième effet secondaire : la déclaration est également autorisée au sein du bloc begin-end de deuxième niveau, la portée étant limitée à ce bloc.
procedure Test; // declaration and initialization in a single statement
begin
var I: Integer := 22;
ShowMessage (I.ToString);
end;
procedure Test1; // multiple inline declarations (symbols declared when used)
begin
var I: Integer := 22;
var J: Integer;
J := 22 + I;
var K: Integer := I + J;
ShowMessage (K.ToString);
end;
procedure Test2; // scope limited to local block
begin
var I: Integer := 22;
if I > 10 then
begin
var J: Integer := 3;
ShowMessage (J.ToString);
end
else
begin
var K: Integer := 3;
ShowMessage (J.ToString); // COMPILER ERROR: “Undeclared identifier: ‘J’”
end;
end;
Comme vous pouvez le voir dans le dernier extrait de code ci-dessus, une variable déclarée à l'intérieur d'un bloc begin-end n'est visible qu'au sein de ce bloc spécifique, et ne l'est plus une fois le bloc terminé. A la fin des instructions if, J et K ne seront plus visibles.
L'effet secondaire ne se limite pas uniquement à la visibilité. Une variable managée, comme une référence d'interface ou un enregistrement, sera correctement nettoyée à la fin du bloc, plutôt qu'à la fin d'une procédure ou d'une méthode :
procedure Test99;
begin
// some code
if (something) then
begin
var Intf: IInterface = GetInterface; // Intf.AddRef
var MRec: TManagedRecord = GetMRecValue; // MRec.Create + MRec.Assign
UseIntf(Intf);
UseMRec(MRec);
end; // Intf.Release and MRec.Destroy are implicitly called at end of scope
// more code
end; // no additional cleanup
Inférence de type pour les variables inline
De plus, le compilateur peut désormais inférer dans certaines circonstances le type d'une variable à l'emplacement de sa déclaration inline en examinant le type de la valeur qu'on lui a assigné.
procedure Test;
begin
var I := 22;
ShowMessage (I.ToString);
end;
Le type de l'expression r-value (plus exactement, ce qui apparaît après :=) est analysé pour déterminer le type de la variable. Certains des types de données sont “développés” vers un type plus large. Ainsi dans l'exemple ci-dessus, la valeur numérique 22 (un ShortInt) est développée en entier (Integer). En règle générale, le type de l'expression située à droite est un type entier et est inférieur à 32 bits, la variable sera déclarée comme un entier 32 bits. Vous pouvez utiliser un type explicite si vous voulez un type spécifique, numérique et inférieur.
Sachez également que seul un identificateur unique peut être déclaré sans type de valeur (à la différence des déclarations de variables générales et des déclarations inline).
Alors que cette fonctionnalité peut vous faire économiser quelques frappes de touche pour un entier ou une chaîne, l'inférence de type de variable peut s'avérer être très pratique pour les types complexes comme les instances de types génériques. Dans l'extrait de code ci-dessous, les types inférés sont “TDictionary<string, Integer>” pour la variable MyDictionary et “TPair<string, Integer>” pour la variable APair.
procedure NewTest;
begin
var MyDictionary := TDictionary<string, Integer>.Create;
MyDictionary.Add ('one', 1);
var APair := MyDictionary.ExtractPair('one');
ShowMessage (APair.Value.ToString)
end;
Constantes inline
En plus des variables, il est désormais possible de définir une déclaration de valeur constante comme étant inline. Cela s'applique aux constantes de types ou aux constantes non typées. Dans ce cas, le type est inféré (une fonctionnalité qui existe depuis longtemps pour les constantes). Voici un exemple :
const M: Integer = (L + H) div 2; // single identifier, with type specifier
const M = (L + H) div 2; // single identifier, without type specifier
Pour les boucles avec une déclaration de variable
Les déclarations de variable inline s'avèrent particulièrement pratiques dans les instructions de boucle, y compris les boucles for-to et les boucles for-in.
for var I: Integer := 1 to 10 do ...
for var Item: TItemType in Collection do...
Vous pouvez simplifier le code en tirant parti de l'inférence de type :
for var I := 1 to 10 do ...
for var Item in Collection do ...
Voici une situation dans laquelle l'utilisation d'une variable avec une portée limitée présente un grand intérêt, comme dans l'extrait de code ci-dessous : l'utilisation de la variable ‘I’ à l'extérieur de la boucle provoque une erreur du compilateur (alors qu'auparavant cela provoquait simplement un avertissement) :
procedure ForTest;
begin
var total := 0;
for var I: Integer := 1 to 10 do
Inc (Total, I);
ShowMessage (total.ToString);
ShowMessage (I.ToString); // compiler error: Undeclared Identifier ‘I’