====== Les boucles ======
Dans cette séquence, nous allons parler des boucles dans Pharo. Les boucles sont des messages qu'on va envoyer à des objets. Il existe plein de types de boucles différents. Ce sont des messages qu'on va envoyer soit à des nombres, à des collections, voire même à des block et ça sera dans certains cas des messages d'itération sur les éléments d'une collection, par exemple.
Voilà un exemple:
4 timesRepeat: [ self doSomething ].
On envoie le message "timesRepeat" à l'entier 4 et on va lui passer en paramètre un block. Si vous vous rappelez, on a vu les blocs dans la séquence précédente. Ce message va permettre de répéter l'évaluation de ce block plusieurs fois, en l'occurrence quatre fois dans cet exemple puisque le receveur du message, c'était 4.
Il existe d'autres types de messages pour effectuer des boucles. Ici, c'est le message "to: do:"
1 to: 100 do:
[ :i | Transcript show: i; space ]
Le message "to: do:" est défini sur la classe Number. Et puis, on va lui passer également en paramètre un block qui est le dernier argument du message et ce block va être exécuté un certain nombre de fois avec un curseur de boucle qui varie depuis le receveur jusqu'au premier argument du message. On a un exemple ici, si on reprend exactement le même exemple, on va envoyer le message to:do à l' entier 1. Dans le block, on va afficher le paramètre du block, le paramètre i à chaque tour de boucle. On voit que dans le Transcript, on a bien tous les entiers qui ont été affichés entre 1 et 100.
Il existe d'autres messages pour effectuer des boucles. Par exemple, on a le message "to:by:do:" pour faire des incréments de plus que par 1. On fait des incréments ici pour contrôler de combien on fait l'incrément, on peut faire des incréments par 3 comme dans cet exemple.
1 to: 100 by: 3 do:
[ :i | Transcript show: i; space ]
À chaque tour de boucle, i va prendre des valeurs de 3 en 3. On voit l'exemple ici, cette fois quand on a exécuté ce morceau de code, on voit bien que i a bien varié de 1 à 100, mais avec un incrément de 3 à chaque fois.
Il existe aussi des itérateurs pour effectuer des boucles. Les itérateurs sont des messages plutôt à envoyer à des objets Collection. Il en existe de toutes sortes. On a par exemple "do:" qui permet d'itérer sur chacun des éléments d'une collection.
* "Collect:" qui permet à la fois d'itérer sur les éléments d'une collection, mais également de récupérer, de collecter les résultats pour les mettre dans une nouvelle collection.
* "Select:" qui permet de sélectionner un ensemble d'éléments à l'intérieur d'une collection, donc de construire une nouvelle collection uniquement avec ceux qu'on aurait sectionnés.
* "Reject:" qui permet d'éliminer les éléments qu'on ne voudrait pas dans une collection.
* "Detect:" qui permet de savoir si un élément existe dans une collection donnée.
* etc
On va en voir quelques-uns, par exemple, "do:" qui est finalement le message le plus courant qu'on utilise.
|aCol|
aCol := #( 12 33 10 2).
aCol do: [ :each | Transcript show:each; space ].
On va envoyer le message "do:" à une collection et on va lui passer un block. À chaque tour de boucle, le block, le paramètre du block, ici "each:" va recevoir d'abord le premier élément de la collection, ensuite le second, jusqu'au dernier élément de la collection.
Voici un autre message qui est "whileTrue:" qui permet également d'effectuer des boucles.
"Color>>atLeastAsLuminentAs"
atLeastAsLuminentAs: aFloat
| revisedColor |
revisedColor := self.
[ revisedColor luminance < aFloat ] whileTrue: [ revisedColor := revisedColor slightlyLighter ].
^ revisedColor
"whileTrue:" est un message qu'on va envoyer à un bloc, donc c'est un message défini sur la classe Block. On a le bloc receveur et on a un bloc d'argument. Je vous donne un exemple concret issu de la classe Color. Dans le block receveur, on a une condition: ce bloc va s'évaluer à une condition, true ou false. En fonction de l'évaluation de ce premier bloc, le receveur, on va déclencher l'exécution ou pas du bloc argument qui est le deuxième bloc, le paramètre de la méthode "whileTrue:".
Il existe une variation de "whileTrue:" sans paramètres qui prend le block receveur, qui l'évalue et si ce bloc s'évalue à vrai ou à faux, il est réévalué une fois supplémentaire.
En fait, on va réévaluer le block tant qu'il s'évalue à vrai. On a exactement les pendants de "whileTrue:" avec les méthodes de "whileFalse" sans paramètres et avec paramètres "WhileFalse:".
Toutes les variations existent en fait dans les classes sur les blocs.
En résumé, sur cette séquence, on a vu que les boucles en Pharo sont exprimées comme des messages normaux envoyés à des objets, que ce soit des entiers, des collections, des blocks. Avec ça, on peut construire énormément de boucles différentes et même en rajouter si on en a envie.