Aller au contenu principal
Version: v20 R4 BETA

Control flow

Quelle que soit la simplicité ou la complexité d’une méthode ou d'une fonction, vous utiliserez toujours un ou plusieurs types de structure de programmation. Les structures de programmation déterminent si et dans quel ordre les lignes d’instructions sont exécutées à l’intérieur d’une méthode. Il existe trois types de structures :

  • Séquentielle: une structure séquentielle est une structure simple et linéaire. Une séquence est une série d'instructions que 4D exécute l'une après l'autre, de la première à la dernière. Une routine d'une ligne, fréquemment utilisée pour les méthodes objets, est le cas le plus simple d'une structure séquentielle. Par exemple : [People]lastName:=Uppercase([People]lastName)

  • Conditionnelle : une structure conditionnelle permet aux méthodes de tester une condition et d’exécuter des séquences d’instructions différentes en fonction du résultat. La condition est une expression booléenne, c'est-à-dire une expression qui est évaluée à vrai ou faux. L’une des structures conditionnelles est la structure If...Else...End if, qui aiguille le déroulement du programme vers une séquence ou une autre. L’autre structure conditionnelle est la structure Case of...Else...End case, qui oriente le programme vers une séquence parmi une ou plusieurs alternatives.

  • Répétitive : Il est très courant, lorsque vous écrivez des méthodes, de rencontrer des cas où vous devez répéter une séquence d’instructions un certain nombre de fois. Pour traiter ces besoins, le langage 4D vous propose plusieurs structures répétitives :

Les boucles sont contrôlées de deux manières : soit elles bouclent jusqu'à ce qu'une condition soit remplie, soit elles bouclent un certain nombre de fois. Chaque structure répétitive peut être utilisée de l’une ou l’autre manière, mais les boucles While et Repeat sont mieux adaptées à la répétition jusqu’à ce qu’une condition soit remplie, alors que les boucles For sont mieux adaptées à la répétition un certain nombre de fois. For each...End for each, destinée à effectuer des boucles dans les objets et les collections, permet de combiner les deux manières.

Note : 4D vous permet d’imbriquer des structures de programmation jusqu’à une “profondeur” de 512 niveaux.

If...Else...End if

La syntaxe de la structure conditionnelle If...Else...End if est la suivante :

 If(Boolean_Expression)
instruction(s)
Else
instruction(s)
End if

A noter que l'élément Else est optionnel, vous pouvez écrire :

 If(Boolean_Expression)
instruction(s)
End if

La structure If...Else...End if permet à votre méthode de choisir dans une alternative, en fonction du résultat, TRUE ou FALSE, d’un test (une expression booléenne). Si l’expression booléenne est TRUE, les instructions qui suivent immédiatement le test sont exécutées. Si l’expression booléenne est FALSE, les instructions suivant la ligne Else sont exécutées. Le Else est optionnel ; lorsqu’il est omis, c’est la première ligne d’instructions suivant le End if (s’il y en a une) qui est exécutée.

A noter que l'expression booléenne est toujours évaluée en totalité. Examinons en particulier le test suivant :

 If(MethodA & MethodB)
...
End if

L'expression n'est TRUE que si les deux méthodes sont mises à TRUE. Or, même si MethodA retourne FALSE, 4D évaluera quand même MethodB, ce qui représente une perte de temps inutile. Dans ce cas, il est préférable d'utiliser une structure du type :

 If(MethodA)
If(MethodB)
...
End if
End if

Le résultat est équivalent et MethodB n'est évaluée que si nécessaire.

Note : L'opérateur ternaire permet d'écrire des expressions conditionnelles sur une seule ligne et peut remplacer une séquence complète d'instructions If...Else.

Exemple

  // Ask the user to enter a name
$Find:=Request(Type a name)
If(OK=1)
QUERY([People];[People]LastName=$Find)
Else
ALERT("You did not enter a name.")
End if
End if
End if

Astuce : Il n'est pas obligatoire que des instructions soient exécutées dans chaque branche de l'alternative. Lorsque vous développez un algorithme, ou lorsque vous poursuivez un but précis, rien ne vous empêche d'écrire :

 If(Expression_booléenne)
Else
instruction(s)
End if

ou :

 If(Expression_booléenne)
instruction(s)
Else
End if

Case of...Else...End case

La syntaxe de la structure conditionnelle Case of...Else...End case est la suivante :

 Case of
:(Expression_booléenne)
instruction(s)
:(Expression_booléenne)
statement(s)
.
.
.

:(Expression_booléenne)
instruction(s)
Else
instruction(s)
End case

A noter que l'élément Else est optionnel, vous pouvez écrire :

 Case of
:(Expression_booléenne)
instruction(s)
:(Expression_booléenne)
statement(s)
.
.
.

:(Expression_booléenne)
instruction(s)
End case

Tout comme la structure If...Else...End if, la structure Case of...Else...End case permet également à votre méthode de choisir parmi plusieurs séquences d’instructions. A la différence de la structure If...Else...End, la structure Case of...Else...End case peut tester un nombre illimité d’expressions booléennes et exécuter la séquence d’instructions correspondant à la valeur TRUE.

Chaque expression booléenne débute par le caractère deux points (:). La combinaison de deux points et d’une expression booléenne est appelée un cas. Par exemple, la ligne suivante est un cas :

:(bValidate=1)

Seules les instructions suivant le premier cas TRUE (et ce, jusqu’au cas suivant) seront exécutées. Si aucun des cas n’est TRUE, aucune instruction n’est exécutée (s'il n'y a pas d'élément Else).

Vous pouvez placer une instruction Else après le dernier cas. Si tous les cas sont FALSE, les instructions suivant le Else seront exécutées.

Exemple

Cet exemple teste une variable numérique et affiche une boîte de dialogue d’alerte comportant un simple mot :

 Case of
:((vResult=1) & (vCondition#2)) //this case will be detected first
... //statement(s)
:(vResult=1)
... Case of
:(vResult=1) //Tester si le chiffre est 1
ALERT("One.") //Si le chiffre est 1, afficher une alerte
:(vResult=2) //Tester si le chiffre est 2
ALERT("Two.") //Si le chiffre est 2, afficher une alerte
:(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
//déclaration(s)
End case //Si le chiffre est 2, afficher une alerte
:(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
//statement(s)
End case

A titre de comparaison, voici la version avec If...Else...End if de la même méthode :

 If(vResult=1) //Tester si le chiffre est 1
ALERT("One.") If(vResult=1) //Test if the number is 1
ALERT("One.") //If it is 1, display an alert
Else
If(vResult=2) //Test if the number is 2
ALERT("Two.") //If it is 2, display an alert
Else
If(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
End if
End if
End if If(vResult=1) //Tester si le chiffre est 1
ALERT("One.") If(vResult=1) //Tester si le chiffre est 1
ALERT("One.") If(vResult=1) //Tester si le chiffre est 1
ALERT("One.") If(vResult=1) //Tester si le chiffre est 1
ALERT("One.") //Si le chiffre est 1, afficher une alerte
Else
If(vResult=2) //Tester si le chiffre est 2
ALERT("Two.") //Si le chiffre est 2, afficher une alerte
Else
If(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
End if
End if
End if //Si le chiffre est 2, afficher une alerte
Else
If(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
End if
End if
End if //Si le chiffre est 2, afficher une alerte
Else
If(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
End if
End if
End if //Si le chiffre est 2, afficher une alerte
Else
If(vResult=3) //Tester si le chiffre est 3
ALERT("Three.") //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
End if
End if
End if //Si le chiffre est 3, afficher une alerte
Else //Si le chiffre n'est pas 1, 2 ou 3, afficher une alerte
ALERT("It was not one, two, or three.")
End if
End if
End if

Rappelez-vous qu’avec une structure de type Case of...Else...End case, seul le premier cas TRUE rencontré est exécuté. Même si d’autres cas sont TRUE, seules les instructions suivant le premier cas TRUE seront prises en compte.

Par conséquent, lorsque vous testez dans la même méthode des cas simples et des cas complexes, vous devez placer les cas complexes avant les cas simples, sinon ils ne seront jamais exécutés. Par exemple, si vous souhaitez traiter le cas simple (vResult=1) et le cas complexe (vResult=1) & (vCondition#2) et que vous structurez la méthode de la manière suivante :

 Case of
:((vResult=1) & (vCondition#2)) //this case will be detected first
... //statement(s)
:(vResult=1)
...

... les instructions associées au cas complexe ne seront jamais exécutées. En effet, pour que ce cas soit TRUE, ses deux conditions booléennes doivent l’être. Or, la première condition est celle du cas simple situé précédemment. Lorsqu'elle est TRUE, le cas simple est exécuté et 4D sort de la structure conditionnelle, sans évaluer le cas complexe. Pour que ce type de méthode fonctionne, vous devez écrire :

 Case of
:(vResult=1) //Test if the number is 1
ALERT("One.") //If it is 1, display an alert
:(vResult=2) //Test if the number is 2
ALERT("Two.") //If it is 2, display an alert
:(vResult=3) //Test if the number is 3
ALERT("Three.") //If it is 3, display an alert
Else //If it is not 1, 2, or 3, display an alert
ALERT("It was not one, two, or three.")
End case

Astuce : Il n'est pas obligatoire que des instructions soient exécutées dans toutes les alternatives. Lorsque vous développez un algorithme, ou lorsque vous poursuivez un but précis, rien ne vous empêche d'écrire :

 Case of
:(Expression_booléenne)
:(Expression_booléenne)
...

:(Expression_booléenne)
instruction(s)
Else
instruction(s)
End case

ou :

 Case of
:(Expression_booléenne)
:(Expression_booléenne)
instruction(s)
...

:(Expression_booléenne)
instruction(s)
Else
instruction(s)
End case

ou :

 Case of
Else
instruction(s)
End case

While...End while

La syntaxe de la structure répétitive (ou boucle) While...End while est la suivante :

 While(Boolean_Expression)
statement(s)
{break}
{continue}
End while

Une boucle While...End while exécute les instructions comprises entre While et End while aussi longtemps que l’expression booléenne est TRUE. Elle teste l’expression booléenne initiale et n’entre pas dans la boucle (et donc n'exécute aucune instruction) si l’expression est à FALSE.

Les instructions break et continue sont décrites ci-dessous.

Il est utile d’initialiser la valeur testée dans l’expression booléenne juste avant d’entrer dans la boucle While...End while. Initialiser la valeur signifie lui affecter un contenu approprié, généralement pour que l’expression booléenne soit TRUE et que le programme entre dans la boucle.

La valeur de l'expression booléenne doit pouvoir être modifiée par un élément situé à l'intérieur de la boucle, sinon elle s'exécutera indéfiniment. La boucle suivante est sans fin car NeverStop est toujours TRUE :

 NeverStop:=True
While(NeverStop)
End while

Si vous vous retrouvez dans une telle situation (où une méthode s'exécute de manière incontrôlée), vous pouvez utiliser les fonctions de débogage de 4D et remonter à la source du problème. Pour plus d'informations sur ce point, reportez-vous à la section Débogueur.

Exemple

 CONFIRM("Add a new record?") //L'utilisateur souhaite-t-il ajouter un enregistrement ? CONFIRM("Add a new record?") //The user wants to add a record?
While(OK=1) // Tant que l'utilisateur accepte
ADD RECORD([aTable]) // Ajouter un nouvel enregistrement
End while // Une boucle While se termine toujours par End while

Dans cet exemple, la valeur de la variable système OK est définie par la commande CONFIRM avant que le programme n’entre dans la boucle. Si l’utilisateur clique sur le bouton OK dans la boîte de dialogue de confirmation, la variable OK prend la valeur 1 et la boucle est exécutée. Dans le cas contraire, la variable OK prend la valeur 0 et la boucle est ignorée. Une fois que le programme entre dans la boucle, la commande ADD RECORD permet de continuer à l’exécuter car elle met la variable système OK à 1 lorsque l’utilisateur sauvegarde l’enregistrement. Lorsque l’utilisateur annule (ne valide pas) le dernier enregistrement, la variable système OK prend la valeur 0 et la boucle s’arrête.

Repeat...Until

La syntaxe de la structure répétitive (ou boucle) Repeat...Until est la suivante :

Repeat
statement(s)
{break}
{continue}
Until(Boolean_Expression)

La boucle Repeat...Until est semblable à la boucle While...End while, à la différence qu’elle teste la valeur de l’expression booléenne après l’exécution de la boucle et non avant. Ainsi, la boucle est toujours exécutée au moins une fois, tandis que si l’expression booléenne est initialement à Faux, la boucle While...End while ne s’exécute pas du tout.

L'autre particularité de la boucle Repeat...Until est qu’elle se poursuit jusqu’à ce que l’expression booléenne soit à TRUE.

Les instructions break et continue sont décrites ci-dessous.

Exemple

Comparez l’exemple suivant avec celui de la boucle While...End while. Vous constatez qu’il n’est pas nécessaire d’initialiser l’expression booléenne — il n’y a pas de commande CONFIRM pour initialiser la variable OK.

 Repeat
ADD RECORD([aTable])
Until(OK=0)

For...End for

La syntaxe de la structure répétitive For...End for est la suivante :

For(Counter_Variable;Start_Expression;End_Expression{;Increment_Expression})
statement(s)
{break}
{continue}
End for

La structure For...End for est une boucle contrôlée par un compteur :

  • La variable compteur Counter_Variable est une variable numérique (Réel ou Entier long) initialisée par For...End for à la valeur spécifiée par Start_Expression.
  • La variable Variable_Compteur est incrémentée de la valeur spécifiée par le paramètre optionnel Increment_Expression à chaque fois que la boucle est exécutée. Si vous ne passez pas de valeur dans Increment_Expression, la variable compteur est incrémentée par défaut de un (1).
  • Lorsque le compteur atteint la valeur définie par End_Expression, la boucle s'arrête.

Important : Les expressions numériques Start_Expression, End_Expression et Increment_Expression sont évaluées une seule fois, au début de la boucle. Si ces expressions sont des variables, leur modification depuis l'intérieur de la boucle n'affectera pas l'exécution de la boucle.

Astuce : En revanche, vous pouvez, si vous le souhaitez, modifier la valeur de la variable Counter_Variable depuis l'intérieur de la boucle et cela affectera l'exécution de la boucle.

  • Généralement, Start_Expression est inférieure à End_Expression.
  • Si les deux expressions sont égales, la boucle ne sera exécutée qu'une fois.
  • Si Start_Expression est supérieure à End_Expression, la boucle ne s'exécutera pas du tout, à moins que vous ne spécifiiez une Increment_Expression négative. Reportez-vous ci-dessous au paragraphe décrivant ce point.

Les instructions break et continue sont décrites ci-dessous.

Exemples élémentaires

  1. La boucle suivante s'exécute 100 fois :
 For(vCounter;1;100)
//Faire quelque chose
End for
  1. L'exemple suivant permet de traiter tous les éléments du tableau anArray :
 For($vlElem;1;Size of array(anArray))
//Faire quelque chose avec l'élément
anArray{$vlElem}:=...
End for
  1. L'exemple suivant permet d'examiner chaque caractère du texte vtSomeText :
 For($vlChar;1;Length(vtSomeText))
//Faire quelque chose avec le caractère si c'est une tabulation
If(Character code(vtSomeText[[$vlChar]])=Tab)
//...
End if
End for
  1. L'exemple suivant permet de traiter tous les enregistrements de la sélection de la table [aTable] :
 FIRST RECORD([aTable])
For($vlRecord;1;Records in selection([aTable]))
//Faire quelque chose avec chaque enregistrement
SEND RECORD([aTable])
//...
// Passer à l'enregistrement suivant
NEXT RECORD([aTable])
End for

La plupart des structures For...End for que vous écrirez dans vos projets ressembleront à celles présentées ci-dessus.

Variable compteur

Décrémenter la variable compteur

Dans certains cas, vous pouvez souhaiter disposer d'une boucle dont la valeur de la variable compteur décroît au lieu de croître. Pour cela, Start_Expression doit être supérieure à End_Expression et Increment_Expression doit être négative. Les exemples suivants effectuent les mêmes tâches que les précédents, mais en sens inverse :

  1. La boucle suivante s'exécute 100 fois :
 For(vCounter;100;1;-1)
//Faire quelque chose
End for
  1. L'exemple suivant permet de traiter tous les éléments du tableau anArray :
 For($vlElem;Size of array(anArray);1;-1)
//Faire quelque chose avec l'élément
anArray{$vlElem}:=...
End for
  1. L'exemple suivant permet d'examiner chaque caractère du texte vtSomeText :
 For($vlChar;Length(vtSomeText);1;-1)
//Faire quelque chose avec le caractère si c'est une tabulation
If(Character code(vtSomeText[[$vlChar]])=Tab)
//...
End if
End for
  1. L'exemple suivant permet de traiter tous les enregistrements de la sélection de la table [aTable] :
 LAST RECORD([aTable])
For($vlRecord;Records in selection([aTable]);1;-1)
//Faire quelque chose avec chaque enregistrement
SEND RECORD([aTable])
//...
//Passer à l'enregistrement précédent
PREVIOUS RECORD([aTable])
End for

Incrementer la variable compteur de plus de 1

Si vous le souhaitez, vous pouvez passer dans Increment_Expression une valeur (positive ou négative) dont la valeur absolue est supérieure à un.

  1. La boucle suivante ne traite que les éléments pairs du tableau anArray :
 For($vlElem;2;Size of array(anArray);2)
//Faire quelque chose avec l'élément 2,4...2n
anArray{$vlElem}:=...
End for

Optimiser l'exécution de For...End for

Vous pouvez utiliser comme compteurs des variables réelles et entières, interprocess, process et locales. Pour des boucles longues, et particulièrement en mode compilé, nous vous conseillons d'employer des variables locales de type Entier long.

  1. Voici un exemple :
 var $vlCounter : Integer //use local Integer variables
For($vlCounter;1;10000)
//Faire quelque chose
End for

Comparaison des structures répétitives

Revenons au premier exemple For...End for. La boucle suivante s'exécute 100 fois :

 For(vCounter;1;100)
//Faire quelque chose
End for

Il est intéressant d'examiner la manière dont les boucles While...End while et Repeat...Until effectuent la même action. Voici la boucle While...End while équivalente :

 $i :=1 // Initialisation du compteur
While ($i<=100) // Boucle 100 fois
// Faire quelque chose
$i :=$i +1 // Il faut incrémenter le compteur
End while

Voici la boucle Repeat...Until équivalente :

 $i :=1 // Initialisation du compteur
Repeat
// Faire quelque chose
$i :=$i +1 // Il faut incrémenter le compteur
Until($i=100) // Boucle 100 fois
tip

La boucle For...End for est généralement plus rapide que les boucles While...End while et Repeat...Until , car 4D teste la condition en interne pour chaque cycle de la boucle et incrémente le compteur. Par conséquent, nous vous conseillons de préférer à chaque fois que c'est possible la structure For...End for.

Structures For...End for emboîtées

Vous pouvez emboîter autant de structures répétitives que vous voulez (dans les limites du raisonnable). Cela s'applique aux structures de type For...End for. Il y a dans ce cas une erreur courante à éviter : assurez-vous d'utiliser une variable compteur différente par structure de boucle.

Voici deux exemples :

  1. L'exemple suivant permet de traiter tous les éléments d'un tableau à deux dimensions :
 For($vlElem;1;Size of array(anArray))
//...
// Faire quelque chose avec la ligne
// ...
For($vlSubElem;1;Size of array(anArray{$vlElem}))
//Faire quelque chose avec l'élément
anArray{$vlElem}{$vlSubElem}:=...
End for
End for
  1. L'exemple suivant construit un tableau de pointeurs vers tous les champs de type Date présents dans la base :
 ARRAY POINTER($apDateFields;0)
$vlElem:=0
For($vlTable;1;Get last table number)
If(Is table number valid($vlTable))
For($vlField;1;Get last field number($vlTable))
If(Is field number valid($vlTable;$vlField))
$vpField:=Field($vlTable;$vlField)
If(Type($vpField->)=Is date)
$vlElem:=$vlElem+1
INSERT IN ARRAY($apDateFields;$vlElem)
$apDateFields{$vlElem}:=$vpField
End if
End if
End for
End if
End for

For each...End for each

La syntaxe de la structure répétitive (ou boucle) For each...End for each est la suivante :

 For each(Current_Item;Expression{;begin{;end}}){Until|While}(Boolean_Expression)}
statement(s)
{break}
{continue}
End for each

La structure For each...End for each exécute le cycle d'instructions définies pour chaque Elément_courant de Expression. Le type de Elément_courant dépend du type de Expression. La boucle For each...End for each peut itérer parmi trois types d'Expression :

  • collections : boucle sur chaque élément de la collection,
  • entity selections : boucle sur chaque entity,
  • objets : boucle sur chaque propriété d'objet.

Le tableau suivant compare les trois types de Pour chaque...Fin de chaque :

Boucle sur collectionsBoucle sur entity selectionsBoucle sur objets
Type Elément_courantVariable du même type que les éléments de la collectionEntityVariable texte
Types d’expressionsCollection (avec des éléments du même type)Entity selectionObject
Nombre de boucles (par défaut)Nombre d'éléments de la collectionNombre d'entités dans la sélectionNombre de propriétés d'objets
Prise en charge de Paramètres début / finOuiOuiNon
  • Le nombre de boucles est évalué au démarrage et ne changera pas en cours de traitement. L'ajout ou la suppression d'éléments pendant la boucle est donc déconseillé car il pourra en résulter une redondance ou un manque d'itérations.
  • Par défaut, les instructions incluses sont exécutées pour chaque valeur de Expression. Il est toutefois possible de sortir de la boucle en testant une condition soit au début de chaque itération (While) ou à la fin de chaque itération (Until).
  • Les paramètres optionnels début et fin peuvent être utilisés avec les collections et les entity selections afin de définir des bornes pour la boucle.
  • La boucle For each...End for each peut être utilisée sur une collection partagée ou un objet partagé. Si vous souhaitez modifier un ou plusieurs éléments des propriétés d'objets ou de la collection dans le code, vous devez utiliser les mots-clés Use...End use. Vous pouvez, si vous le souhaitez, appeler les mots-clés Use...End use :
    • avant de saisir la boucle, si les éléments doivent être modifiés ensemble pour des raisons d'intégrité, ou bien
    • dans la boucle, lorsque quelques éléments/propriétés seulement doivent être modifiés et qu'aucune gestion de l'intégrité n'est requise.

Les instructions break et continue sont décrites ci-dessous.

Boucle sur collections

Lorsque For each...End for each est utilisée avec une Expression de type Collection, le paramètre Elément_courant est une variable du même type que les éléments de la collection. Par défaut, le nombre de boucles est basé sur le nombre d'éléments de la collection.

La collection doit contenir uniquement des éléments du même type. Dans le cas contraire, une erreur sera retournée dès que la première valeur de type différent sera assignée à la variable Elément_courant.

A chaque itération de la boucle, la variable Elément_courant reçoit automatiquement l'élément correspondant de la collection. Vous devez tenir compte des points suivants :

  • If the Current_Item variable is of the object type or collection type (i.e. If any collection item is not of the same type as the variable, an error is generated and the loop stops.
  • If the Current_Item variable is of the object type or collection type (i.e. Si un seul élément de la collection n'est pas du même type que la variable, une erreur est générée et la boucle s'arrête.
  • Si la collection contient des éléments de valeur Null, une erreur sera générée si le type de la variable Elément_courant ne prend pas en charge la valeur Null (comme par exemple les variables entier long).

Exemple

Vous souhaitez calculer quelques statistiques sur une collection de nombres :

 var $nums : Collection
$nums:=New collection(10;5001;6665;33;1;42;7850)
var $item;$vEven;$vOdd;$vUnder;$vOver : Integer
For each($item;$nums)
If($item%2=0)
$vEven:=$vEven+1
Else
$vOdd:=$vOdd+1
End if
Case of
:($item<5000)
$vUnder:=$vUnder+1
:($item>6000)
$vOver:=$vOver+1
End case
End for each
//$vEven=3, $vOdd=4
//$vUnder=4,$vOver=2

Boucle sur entity selections

Lorsque For each...End for each est utilisé avec une Expression du type Entity selection , le paramètre Current_Item est l'entité en cours de traitement.

Le nombre de boucles est basé sur le nombre d'entities présentes dans l'entity selection. A chaque itération de la boucle, le paramètre Elément_courant reçoit automatiquement l'entity qui est en cours de traitement.

Note : Si l'entity selection contient une entity qui a été supprimée entre-temps par un autre process, elle est automatiquement ignorée durant la boucle.

Keep in mind that any modifications applied on the current entity must be saved explicitly using entity.save().

Exemple

Vous souhaitez augmenter le salaire de tous les employés britanniques dans une entity selection :

 var emp : Object
For each(emp;ds.Employees.query("country='UK'"))
emp.salary:=emp.salary*1,03
emp.save()
End for each

Boucles sur des propriétés d'objets

Lorsque For each...End for each est utilisée avec une Expression de type Objet, le paramètre Elément_courant est une variable texte qui reçoit automatiquement le nom de la propriété en cours de traitement.

Les propriétés de l'objet sont itérées en fonction de leur ordre de création. Pendant la boucle, il est possible d'ajouter ou de supprimer des propriétés dans l'objet, sans pour autant modifier le nombre de boucles qui reste basé sur le nombre de propriétés initial de l'objet.

Exemple

Vous souhaitez passer en majuscules les propriétés contenant des noms dans l'objet suivant :

{
"firstname": "gregory",
"lastname": "badikora",
"age": 20
}

Vous pouvez écrire :

 For each($property;$vObject)
If(Value type($vObject[$property])=Is text)
$vObject[$property]:=Uppercase($vObject[$property])
End if
End for each
{
"firstname": "GREGORY",
"lastname": "BADIKORA",
"age": 20
}

Paramètres début / fin

Vous pouvez définir des bornes pour l'itération à l'aide des paramètres optionnels début et fin.

Note : Les paramètres début et fin sont utilisables uniquement avec les boucles sur des collections et des entity selections (ils sont ignorés avec les boucles sur des propriétés d'objets).

  • Dans le paramètre début, passez la position de l'élément de Expression auquel démarrer l'itération (début est inclus).
  • Dans le paramètre fin, vous pouvez passer la position de l'élément de Expression auquel stopper l'itération (fin est exclus).

Si fin est omis ou si fin est plus grand que le nombre d'éléments de Expression, les éléments sont itérés depuis début jusqu'au dernier inclus. Si les paramètres début et fin sont des valeurs positives, ils représentent des positions d'éléments dans Expression. Si begin est une valeur négative, elle est recalculée comme begin:=begin+Taille expression (elle est considérée comme un décalage à partir de la fin de Expression). Si la valeur calculée est négative, begin prend la valeur 0. Note : Même si début est une valeur négative, l'itération est toujours effectuée dans le même ordre. Si fin est une valeur négative, elle est recalculée comme fin:=fin+Taille expression

Par exemple :

  • une collection contient 10 éléments (numérotés de 0 à 9)
  • début=-4 > début=-4+10=6 > l'itération démarre au 6e élément (numéro 5)
  • fin=-2 > fin=-2+10=8 > l'itération stoppe avant le 8e élément (numéro 7), i.e.

Exemple

 var $col;$col2 : Collection
$col:=New collection("a";"b";"c";"d";"e")
$col2:=New collection(1;2;3)
var $item : Text
For each($item;$col;0;3)
$col2.push($item)
End for each
//$col2=[1,2,3,"a","b","c"]
For each($item;$col;-2;-1)
$col2.push($item)
End for each
//$col2=[1,2,3,"a","b","c","d"]

Conditions Until et While

Vous pouvez contrôler l'exécution de For each...End for each en ajoutant une condition Jusque ou Tant que à la boucle. Lorsqu'une instruction Until(condition) est associée à la boucle, l'itération stoppe dès que la condition est évaluée à True, tandis que dans le cas d'une instruction While(condition), l'itération stoppe dès que la condition est évaluée à False.

Vous pouvez passer un mot-clé ou l'autre en fonction de vos besoins :

  • La condition Until est testée à la fin de chaque itération, donc si Expression n'est ni vide ni Null, la boucle sera exécutée au moins une fois.
  • La condition While est testée au début de chaque itération, donc en fonction du résultat de la condition, la boucle peut ne pas être exécutée du tout.

Exemple

 $colNum:=New collection(1;2;3;4;5;6;7;8;9;10)

$total:=0
For each($num;$colNum)While($total<30) //testé au début
$total:=$total+$num
End for each
ALERT(String($total)) //$total = 36 (1+2+3+4+5+6+7+8)

$total:=1000
For each($num;$colNum)Until($total>30) //testé à la fin
$total:=$total+$num
End for each
ALERT(String($total)) //$total = 1001 (1000+1)

break et continue

Toutes les structures de boucles ci-dessus prennent en charge les instructions break et continue. Ces instructions vous donnent plus de contrôle sur les boucles en vous permettant de sortir de la boucle et de contourner, à tout moment, l'itération en cours.

break

L'instruction break met fin à la boucle qui la contient. Le contrôle du programme passe à l'instruction située immédiatement après le corps de la boucle.

Si l'instruction break se trouve à l'intérieur d'une boucle imbriquée (boucle dans une autre boucle), l'instruction break mettra fin à la boucle la plus interne.

Exemple

For (vCounter;1;100)
If ($tab{vCounter}="") //si une condition devient vraie
break //fin de la boucle For
End if
End for

continue

L'instruction continue met fin à l'exécution des instructions de l'itération de la boucle courante, et poursuit l'exécution de la boucle à l'itération suivante.

var $text : Text
For ($i; 0; 9)
If ($i=3)
continue //traite directement l'itération suivante
End if
$text:=$text+String($i)
End for
// $text="012456789"

return {expression}

Historique
VersionModifications
v19 R4Ajout

L'instruction return peut être appelée de n'importe où. Lorsqu'une instruction return est utilisée dans une fonction ou une méthode, l'exécution de la fonction ou de la méthode est arrêtée. Le code restant n'est pas exécuté et le contrôle est renvoyé à l'appelant.

L'instruction return peut être utilisée pour retourner une valeur à l'appelant.

Exemple

var $message : Text
var $i : Integer

While (True) //boucle infinie
$i:=$i+1
$message+=String($i)+"A\r" // jusqu'à 5
logConsole($message)
If ($i=5)
return //stops the loop
End if
$message+=String($i)+"B\r" // jusqu'à 4
logConsole($message)
End while
$message+=String($i)+"C\r" //jamais exécutée
logConsole($message)

// 1A
// 1B
// 2A
// 2B
// 3A
// 3B
// 4A
// 4B
// 5A