WEBVTT

00:00:00.660 --> 00:00:03.030 align:middle
Dans cette séquence, on
va voir les itérateurs.

00:00:03.230 --> 00:00:05.330 align:middle
On va revenir sur les
collections et voir comment est-ce

00:00:05.530 --> 00:00:08.720 align:middle
qu'on peut les parcourir
facilement, grâce aux itérateurs en Pharo.

00:00:09.300 --> 00:00:12.250 align:middle
Vous allez comprendre la
puissance des itérateurs en

00:00:12.450 --> 00:00:14.840 align:middle
Pharo, et puis je vais
vous donner un panorama des

00:00:15.040 --> 00:00:17.470 align:middle
principaux itérateurs que vous
pouvez utiliser sur vos collections

00:00:18.170 --> 00:00:21.270 align:middle
Juste un exemple. Ça,
c'est le code que vous devriez

00:00:21.470 --> 00:00:25.330 align:middle
écrire par exemple en Java
pour parcourir une collection.

00:00:25.630 --> 00:00:29.200 align:middle
Je veux parcourir une
collection "person", pour extraire

00:00:29.400 --> 00:00:31.900 align:middle
la liste des noms de ces
personnes, de ces objets "person".

00:00:32.730 --> 00:00:35.640 align:middle
En fait en Pharo, on
écrirait plutôt ce code-là, on

00:00:35.840 --> 00:00:38.890 align:middle
utiliserait un itérateur,
qu'on reverra dans la suite du

00:00:39.090 --> 00:00:43.000 align:middle
cours, "collect", où on va
collecter l'ensemble des noms des personnes.

00:00:44.200 --> 00:00:47.760 align:middle
En Java 8 pour l'anecdote,
la dernière version de Java,

00:00:48.210 --> 00:00:52.100 align:middle
ils ont introduit la notion
de blocks, l'équivalent des

00:00:52.300 --> 00:00:54.130 align:middle
blocks SmallTalk, les
fermetures lexicales, qui leur

00:00:54.330 --> 00:00:57.000 align:middle
permet d'avoir une syntaxe qui
est proche de celle de Pharo.

00:00:57.220 --> 00:00:59.560 align:middle
Sauf qu'en Pharo, on l'a
depuis très longtemps, depuis le

00:00:59.760 --> 00:01:04.180 align:middle
début et elle est au cœur
du langage, ce qui donne une

00:01:04.420 --> 00:01:06.470 align:middle
puissance d'expression aux
 programmeurs assez importante.

00:01:08.580 --> 00:01:11.460 align:middle
Les itérateurs, il en existe plein.

00:01:11.660 --> 00:01:13.580 align:middle
Le premier qu'on
voit, c'est "collect".

00:01:13.910 --> 00:01:16.620 align:middle
A quoi sert collect quand
je l'envoie à une collection?

00:01:16.820 --> 00:01:18.900 align:middle
Ici on a une collection de
nombres, donc des nombres

00:01:19.100 --> 00:01:21.590 align:middle
positifs et des nombres
négatifs. J'envoie le message

00:01:21.790 --> 00:01:23.430 align:middle
"collect" à cette
collection et je lui passe un block.

00:01:23.810 --> 00:01:26.660 align:middle
A chaque tour de la
collection, le paramètre du block

00:01:26.860 --> 00:01:29.920 align:middle
vaudra successivement 2,
moins 3, 4, et caetera.

00:01:30.260 --> 00:01:33.560 align:middle
Et puis on va envoyer le
abs, donc abs c'est absolu.

00:01:33.760 --> 00:01:36.590 align:middle
Donc ça veut dire qu'on va
demander la valeur absolue de ce nombre.

00:01:37.830 --> 00:01:39.620 align:middle
Une fois qu'on aura
appliqué ce block à chacun des

00:01:39.820 --> 00:01:41.920 align:middle
éléments de la
collection, on va agréger tous les

00:01:42.120 --> 00:01:43.170 align:middle
résultats dans une
nouvelle collection.

00:01:43.760 --> 00:01:45.410 align:middle
On voit que le résultat
rendu par collect c'est une

00:01:45.610 --> 00:01:48.900 align:middle
nouvelle collection, telle
qu'on a appliqué ce block à

00:01:49.100 --> 00:01:50.180 align:middle
chacun des éléments de la collection.

00:01:50.540 --> 00:01:52.740 align:middle
On a pris la valeur absolue
de 2; la valeur absolue de

00:01:52.940 --> 00:01:56.120 align:middle
moins 3, donc 3; la valeur
absolue de 4, 4; la valeur

00:01:56.320 --> 00:01:59.910 align:middle
absolue de moins 35, ça fait 35 et
la valeur absolue de 4 ça fait 4.

00:02:01.720 --> 00:02:06.440 align:middle
Le point à retenir qui est vraiment
intéressant, c'est qu'on pense objet.

00:02:07.050 --> 00:02:09.400 align:middle
On demande à la collection
de faire quelque chose pour

00:02:09.600 --> 00:02:12.760 align:middle
nous, donc c'est la
collection qui va se parcourir les

00:02:13.000 --> 00:02:15.630 align:middle
éléments qu'elle contient
elle-même et on va lui fournir

00:02:15.830 --> 00:02:17.200 align:middle
le traitement à appliquer
sur chacun des éléments.

00:02:17.530 --> 00:02:19.400 align:middle
C'est là qu'est le
secret des itérateurs.

00:02:21.200 --> 00:02:22.930 align:middle
Voici un nouvel exemple de collect.

00:02:23.670 --> 00:02:26.110 align:middle
J'ai une collection ici,
je lui envoie le message

00:02:26.440 --> 00:02:30.900 align:middle
"collect" et dans le block
je vais à chaque fois demander

00:02:31.720 --> 00:02:33.900 align:middle
"Est-ce que l'élément est impair ?".

00:02:34.460 --> 00:02:36.820 align:middle
Et donc ici pour le premier
élément, je vais agréger tous

00:02:37.020 --> 00:02:39.860 align:middle
les résultats: false,
true, false et true.

00:02:44.840 --> 00:02:49.390 align:middle
Vous pouvez naturellement
écrire ce qu'on aurait l'habitude

00:02:49.590 --> 00:02:51.630 align:middle
d'écrire dans notre
langage où les blocks et les

00:02:51.830 --> 00:02:54.240 align:middle
itérateurs n'existent pas,
donc on pourrait écrire "Je

00:02:54.440 --> 00:02:57.950 align:middle
prends la collection, je
vais construire une collection

00:02:58.150 --> 00:03:01.830 align:middle
de résultats et je vais
parcourir de 1 à la taille de la

00:03:02.030 --> 00:03:03.020 align:middle
collection, collection size.

00:03:03.660 --> 00:03:04.820 align:middle
Je vais utiliser un do.

00:03:05.110 --> 00:03:07.580 align:middle
Et puis je vais parcourir la
collection et à chaque fois

00:03:07.780 --> 00:03:09.470 align:middle
ajouter dans la
collection le résultat.

00:03:09.670 --> 00:03:12.280 align:middle
" On peut écrire tout ça et
c'est complètement équivalent à ça.

00:03:12.660 --> 00:03:14.310 align:middle
A vous de choisir votre
camp: est-ce que vous voulez

00:03:14.510 --> 00:03:16.750 align:middle
écrire quelque chose de simple ou
quelque chose de plus compliqué?

00:03:17.200 --> 00:03:18.730 align:middle
En gros, la question est là.

00:03:19.340 --> 00:03:21.820 align:middle
Personnellement, je préfère
clairement cette première solution.

00:03:24.770 --> 00:03:26.750 align:middle
Il existe dans la
hiérarchie des collections Pharo

00:03:28.460 --> 00:03:30.510 align:middle
quelque chose de
fondamental, c'est que toutes les

00:03:30.710 --> 00:03:32.940 align:middle
collections sont
polymorphiques et héritent de la classe

00:03:33.140 --> 00:03:34.800 align:middle
collection et on a une API commune.

00:03:35.440 --> 00:03:38.510 align:middle
L'avantage, c'est que
les itérateurs aussi vont

00:03:39.000 --> 00:03:42.760 align:middle
fonctionner sur la
plupart des collections.

00:03:46.260 --> 00:03:48.270 align:middle
L'idée, c'est
vraiment de penser objet.

00:03:48.470 --> 00:03:51.200 align:middle
On demande à la collection
d'itérer sur ces éléments pour

00:03:51.400 --> 00:03:52.870 align:middle
nous, puisque on ne sait
pas si on est en train de

00:03:53.070 --> 00:03:56.290 align:middle
manipuler un dictionnaire
ou on n'a pas envie de savoir

00:03:56.490 --> 00:03:58.590 align:middle
comment sont représentées les
clefs, les valeurs, et cetera.

00:03:59.550 --> 00:04:02.470 align:middle
Donc on va vraiment demander
"Collection, parcours-toi et

00:04:02.670 --> 00:04:04.310 align:middle
applique ce
traitement sur tes éléments.

00:04:06.810 --> 00:04:07.570 align:middle
"

00:04:07.770 --> 00:04:09.810 align:middle
Il existe beaucoup d'itérateurs
qui vont permettre de faire ça.

00:04:10.040 --> 00:04:11.380 align:middle
On a vu le do, le collect.

00:04:11.610 --> 00:04:14.600 align:middle
On en a d'autres: select,
rejet, detect, et caetera, on

00:04:14.800 --> 00:04:17.630 align:middle
va en voir quelques uns dans
la suite de cette séquence.

00:04:19.680 --> 00:04:23.530 align:middle
Le do, c'est l'itérateur
le plus simple qui permet de

00:04:23.730 --> 00:04:25.450 align:middle
parcourir chacun des
éléments de ma collection et je les

00:04:25.650 --> 00:04:28.100 align:middle
affiche ici dans le
Transcript. Celui-là, on l'a déjà vu

00:04:28.300 --> 00:04:30.130 align:middle
plein de fois dans
les autres exemples.

00:04:31.000 --> 00:04:33.280 align:middle
Un nouvel itérateur qui est select.

00:04:33.720 --> 00:04:36.940 align:middle
Je veux récupérer tous les
éléments de la collection qui

00:04:37.140 --> 00:04:39.250 align:middle
répondent à un critère donné.

00:04:39.450 --> 00:04:41.870 align:middle
Ici, je veux tous les
éléments impairs de la collection.

00:04:42.300 --> 00:04:46.800 align:middle
J'envoie "select" à la
collection, je passe un block et à

00:04:47.000 --> 00:04:50.610 align:middle
chaque fois que ce bloc va
s'évaluer à "Vrai", l'élément

00:04:50.810 --> 00:04:52.600 align:middle
en question sera ajouté
dans la collection résultats.

00:04:55.320 --> 00:04:58.190 align:middle
C'est complètement
équivalent à select: odd.

00:04:59.530 --> 00:05:02.790 align:middle
Quand j'ai un un bloc ici
ou ce qui constitue seulement

00:05:03.000 --> 00:05:05.940 align:middle
un envoi de message à
l'élément de la collection, le

00:05:06.140 --> 00:05:08.370 align:middle
paramètre du block, je peux
mettre directement sous la

00:05:08.570 --> 00:05:11.120 align:middle
forme d'un symbole le
nom du message à envoyer.

00:05:11.320 --> 00:05:15.380 align:middle
C'est encore plus concis et ça ne
marche que pour les messages unaires.

00:05:18.020 --> 00:05:20.510 align:middle
On peut utiliser d'autres
types d'itérateurs comme reject.

00:05:21.100 --> 00:05:23.610 align:middle
Je veux éliminer tous les
éléments de la collection qui

00:05:23.810 --> 00:05:26.080 align:middle
sont impairs et donc, dans
la collection résultats, il ne

00:05:26.280 --> 00:05:27.090 align:middle
va me rester que des éléments pairs.

00:05:28.610 --> 00:05:31.330 align:middle
Ou alors, je veux faire un
detect, je veux détecter le

00:05:31.530 --> 00:05:33.620 align:middle
premier élément de la
collection qui répond à un critère

00:05:33.820 --> 00:05:37.350 align:middle
donné pour lequel
l'évaluation du bloc va être vraie.

00:05:37.550 --> 00:05:40.440 align:middle
Je veux le premier élément de la
collection qui est impair, donc 11.

00:05:42.720 --> 00:05:45.760 align:middle
Dans certains cas, on veut
détecter le premier élément de

00:05:45.960 --> 00:05:47.660 align:middle
la collection qui répond à
un critère, mais s'il n'y en a

00:05:47.860 --> 00:05:50.120 align:middle
pas alors on aimerait bien
avoir une valeur par défaut.

00:05:50.590 --> 00:05:54.090 align:middle
C'est "detect: ifNone", donc
s'il n'y a aucun élément c'est

00:05:54.940 --> 00:05:57.680 align:middle
l'évaluation de ce block
là qui va être effectuée, et

00:05:57.880 --> 00:05:58.720 align:middle
donc ça va bien nous renvoyer 0.

00:06:00.190 --> 00:06:03.410 align:middle
Il y a d'autres
itérateurs encore qui vont encore

00:06:03.610 --> 00:06:06.000 align:middle
faciliter la vie du
 programmeur. Par exemple, le "anySatisfy".

00:06:06.180 --> 00:06:09.920 align:middle
Est-ce qu'il existe dans
la collection un élément qui

00:06:10.120 --> 00:06:11.830 align:middle
répond à ce critère-là? Je
veux tous les éléments d'une

00:06:12.030 --> 00:06:13.460 align:middle
collection qui
répondent à un critère donné.

00:06:13.660 --> 00:06:16.210 align:middle
Je veux parcourir la
collection à l'envers en partant de

00:06:16.410 --> 00:06:19.040 align:middle
la fin vers le début. Je
veux parcourir la collection en

00:06:19.240 --> 00:06:21.510 align:middle
ayant un curseur d'index. Je
veux parcourir les éléments

00:06:21.710 --> 00:06:22.470 align:middle
de la collection 2 à 2.

00:06:22.670 --> 00:06:24.300 align:middle
Je veux parcourir toutes
les permutations circulaires

00:06:24.500 --> 00:06:25.630 align:middle
possibles des
éléments d'une collection.

00:06:26.770 --> 00:06:29.640 align:middle
Il y en a beaucoup des
itérateurs et on peut en

00:06:29.840 --> 00:06:33.330 align:middle
construire des nouveaux,
d'ailleurs. Ici, je veux

00:06:33.530 --> 00:06:37.680 align:middle
parcourir une collection 1, 2, 3
couplée avec une deuxième collection.

00:06:39.000 --> 00:06:42.570 align:middle
Dans mon bloc do,
j'aurai x et y, 2 paramètres.

00:06:43.190 --> 00:06:46.590 align:middle
Le premier x, ça sera
un élément de la première

00:06:46.790 --> 00:06:48.740 align:middle
collection, et y un élément
de la deuxième collection.

00:06:49.160 --> 00:06:51.420 align:middle
Donc je vais pouvoir
multiplier ces éléments entre eux.

00:06:51.620 --> 00:06:52.840 align:middle
On obtient bien 10, 40 et 90.

00:06:55.050 --> 00:06:57.100 align:middle
Et bien évidemment, il
faut absolument que les 2

00:06:57.300 --> 00:06:58.790 align:middle
collections aient la même
taille avec cet itérateur-là.

00:07:01.510 --> 00:07:04.200 align:middle
On peut avoir
d'autres types de parcours.

00:07:04.400 --> 00:07:06.840 align:middle
Ici, j'utilise le "do separatedBy".

00:07:08.590 --> 00:07:10.640 align:middle
J'ai une collection, je
vais parcourir chacun des

00:07:10.840 --> 00:07:14.140 align:middle
éléments et à chaque fois
que j'ai parcouru un élément,

00:07:14.340 --> 00:07:17.670 align:middle
je vais évaluer un bloc ici qui
correspond à l'affichage d'une virgule.

00:07:18.040 --> 00:07:21.140 align:middle
Ça va me permettre de
parcourir le A, afficher une

00:07:21.340 --> 00:07:23.210 align:middle
virgule, afficher le B,
afficher une virgule, afficher le C.

00:07:23.410 --> 00:07:26.340 align:middle
A chaque fois entre chaque élément,
je vais avoir effectué une action.

00:07:29.000 --> 00:07:32.350 align:middle
Ici, j'ai un itérateur qui
est "GroupBy", qui me permet

00:07:32.550 --> 00:07:37.510 align:middle
de grouper les éléments d'une
collection en fonction d'un critère.

00:07:39.040 --> 00:07:41.610 align:middle
J'envoie ce message à la
collection 1, 2, 3, 4, 5, 6, 7

00:07:41.810 --> 00:07:45.330 align:middle
ici et je récupère en
résultat un dictionnaire.

00:07:47.170 --> 00:07:50.010 align:middle
Donc tous les éléments
qui ont répondu "Faux" à ce

00:07:50.210 --> 00:07:52.580 align:middle
critère, le critère
c'était "even" c'est les éléments

00:07:52.780 --> 00:07:54.740 align:middle
pairs, donc on voit que ça
contient bien une collection

00:07:54.940 --> 00:07:57.300 align:middle
de tous les éléments
impairs. Et tout ce qui a répondu

00:07:57.500 --> 00:07:59.000 align:middle
"Vrai", c'est tous les éléments

00:08:02.370 --> 00:08:03.130 align:middle
pairs.

00:08:03.330 --> 00:08:04.290 align:middle
Quand on a une collection
souvent quand on fait des

00:08:04.490 --> 00:08:06.670 align:middle
calculs on a tendance à
imbriquer des collections dans

00:08:06.870 --> 00:08:10.510 align:middle
des collection, et on se
retrouve avec des niveaux d'imbrication

00:08:10.710 --> 00:08:11.470 align:middle
qui peuvent être importants.

00:08:11.960 --> 00:08:15.190 align:middle
Ici, vous avez un exemple
construit à la main où on a des

00:08:15.390 --> 00:08:17.310 align:middle
collections qui sont
imbriquées dans des collections.

00:08:18.070 --> 00:08:20.890 align:middle
Ce qu'on aimerait c'est
arriver à aplatir la collection,

00:08:21.090 --> 00:08:22.180 align:middle
à mettre tous les
éléments au même niveau.

00:08:23.180 --> 00:08:27.690 align:middle
Pour ça, on a quelque chose
de facile en Pharo, on a un

00:08:27.890 --> 00:08:28.830 align:middle
itérateur qui
s'appelle "flatCollect".

00:08:29.030 --> 00:08:30.800 align:middle
C'est-à-dire que je vais
parcourir les éléments et

00:08:31.000 --> 00:08:32.850 align:middle
construire une nouvelle
collection dans laquelle j'ai tout aplati.

00:08:35.400 --> 00:08:38.710 align:middle
Donc on obtient bien la
collection 1, 2, 3, 4, 5, 6 dans

00:08:38.910 --> 00:08:40.490 align:middle
laquelle on a enlevé tous
les niveaux d'imbrication.

00:08:45.240 --> 00:08:47.480 align:middle
Le secret, ce n'est pas
de vous présenter tous les

00:08:47.680 --> 00:08:50.130 align:middle
itérateurs disponibles dans
Pharo, ce serait long et fastidieux.

00:08:50.330 --> 00:08:52.170 align:middle
L'idée, c'est vraiment de
vous montrer qu'il en existe

00:08:52.370 --> 00:08:54.620 align:middle
plein et que vous pouvez
découvrir vraiment les vôtres en

00:08:54.820 --> 00:08:57.500 align:middle
allant lire les méthodes qui
existent sur les classes des

00:08:57.700 --> 00:08:59.460 align:middle
collections, en allant
découvrir ces méthodes.

00:09:00.400 --> 00:09:02.240 align:middle
Un exemple simple, c'est de
commencer par les itérateurs

00:09:02.440 --> 00:09:04.260 align:middle
que vous connaissez. Par
exemple, se poser la question

00:09:04.460 --> 00:09:06.420 align:middle
"Comment est-ce
qu'est implémenté le do?"

00:09:06.620 --> 00:09:08.850 align:middle
Je cherche le do dans la
hiérarchie des collections, je

00:09:09.050 --> 00:09:09.840 align:middle
vais voir qu'il est implémenté dans

00:09:10.040 --> 00:09:13.420 align:middle
"SequenceableCollection",
toutes les collections séquençables.

00:09:14.220 --> 00:09:16.580 align:middle
Donc la méthode "do", elle
prend en paramètre un block.

00:09:16.900 --> 00:09:19.180 align:middle
Et voici
l'implémentation de cette collection.

00:09:19.630 --> 00:09:23.190 align:middle
1 a la taille de la
collection do et j'ai un block.

00:09:23.540 --> 00:09:27.000 align:middle
Je vais évaluer le block
qui est passé en paramètre en

00:09:27.200 --> 00:09:29.310 align:middle
lui passant l'élément à l'indice I.

00:09:30.330 --> 00:09:31.090 align:middle
Donc c'est tout simple.

00:09:32.350 --> 00:09:36.550 align:middle
Les itérateurs sont
extrêmement puissants en Pharo, comme

00:09:36.750 --> 00:09:40.650 align:middle
on a pu le voir. Toutes les
collections supportent ces

00:09:40.850 --> 00:09:41.850 align:middle
itérateurs de façon polymorphique.

00:09:42.350 --> 00:09:45.470 align:middle
Du point de vue programmeur,
on utilise des itérateurs et

00:09:45.670 --> 00:09:47.290 align:middle
puis c'est chacune des
 classes de collections qui vont

00:09:47.490 --> 00:09:50.500 align:middle
les implémenter de façon
adéquate par rapport à la

00:09:50.700 --> 00:09:51.550 align:middle
collection qu'ils représentent.

00:09:52.880 --> 00:09:55.450 align:middle
On peut en définir des
nouveaux, extrêmement intéressants.

00:09:55.650 --> 00:09:57.520 align:middle
Je peux définir mes propres
itérateurs si j'en ai envie

00:09:57.720 --> 00:09:58.700 align:middle
sur les classes de collections.

00:10:00.550 --> 00:10:02.010 align:middle
Il y a une subtilité.

00:10:02.210 --> 00:10:05.310 align:middle
Pour ceux qui connaissent le
Design pattern iterator, en

00:10:05.510 --> 00:10:08.770 align:middle
fait la différence c'est
que le développeur ne contrôle

00:10:09.000 --> 00:10:10.540 align:middle
pas quand il passe
à l'élément suivant.

00:10:10.740 --> 00:10:14.260 align:middle
C'est la collection, qui en interne,
décide de passer à l'élément suivant.

00:10:14.460 --> 00:10:17.820 align:middle
On n'envoie pas explicitement
le message "next" à l'itérateur.

00:10:18.020 --> 00:10:20.120 align:middle
C'est une subtilité pour ceux qui
connaissent le Design pattern iterator.

00:10:21.690 --> 00:10:26.360 align:middle
En résumé, les itérateurs
sont vraiment puissants et

00:10:27.040 --> 00:10:30.810 align:middle
un allié fort du programmeur qui vont
faciliter l'écriture des programmes.

00:10:31.010 --> 00:10:33.470 align:middle
On l'a vu, ça permet
d'écrire du code concis, simple et

00:10:33.670 --> 00:10:38.210 align:middle
élégant et ça permet de garantir l'

00:10:38.410 --> 00:10:39.880 align:middle
encapsulation des données
au sein d'une collection.

