1 00:00:00,470 --> 00:00:02,430 Bonjour. Dans cette séquence on va voir la réflexion. 2 00:00:03,790 --> 00:00:07,050 Donc on va aussi discuter de la capacité d'introspection 3 00:00:07,340 --> 00:00:08,860 dans Pharo et pourquoi c'est intéressant. 4 00:00:09,700 --> 00:00:14,270 Donc un système réflexif, la réflexion se décompose en 2 5 00:00:15,380 --> 00:00:17,160 grandes familles, l'introspection. 6 00:00:17,360 --> 00:00:21,330 L'introspection, c'est la capacité d'un programme à s'observer lui-même. 7 00:00:21,530 --> 00:00:24,240 Et l'intercession, c'est la capacité d'un programme à se 8 00:00:24,440 --> 00:00:28,900 modifier lui-même, a modifié donc son état, sa propre interprétation. 9 00:00:30,740 --> 00:00:35,000 Donc la réification, c'est un concept qui consiste à 10 00:00:35,200 --> 00:00:38,320 exprimer, à expliciter sous-forme d'objets, des choses 11 00:00:38,520 --> 00:00:42,840 qui sont normalement implicites. Par exemple, la pile d'exécution, 12 00:00:43,040 --> 00:00:45,630 la stack en Pharo est explicite. 13 00:00:46,060 --> 00:00:49,090 En fait, on peut y avoir accès sous la forme d'un objet classique. 14 00:00:50,040 --> 00:00:53,010 Donc plus classiquement, la notion de classe, une classe 15 00:00:53,210 --> 00:00:55,140 en Pharo c'est un objet tout à fait classique. 16 00:00:55,560 --> 00:00:57,000 Dans un autre langage, ce n'est vraiment pas le cas. 17 00:00:57,180 --> 00:00:58,250 Les classes ne sont pas des objets. 18 00:01:00,150 --> 00:01:04,110 Donc, un système réflexif comme je le disais, il a une 19 00:01:04,310 --> 00:01:06,510 propre représentation de lui-même d'accord. 20 00:01:07,070 --> 00:01:09,000 Il est capable de se représenter lui-même. 21 00:01:09,870 --> 00:01:14,690 Et puis, il peut agir sur cette représentation pour se modifier lui-même. 22 00:01:15,110 --> 00:01:17,540 Et lorsqu'il se modifie, ça change son état mais ça 23 00:01:17,740 --> 00:01:20,240 change aussi sa représentation, d'accord. 24 00:01:20,530 --> 00:01:25,410 Donc on parle de lien causal entre sa représentation et son état. 25 00:01:25,710 --> 00:01:28,380 Si on change l'état, si l'état change, la représentation 26 00:01:28,580 --> 00:01:30,680 du système change et si on change la représentation du 27 00:01:30,880 --> 00:01:32,150 système, ça change l'état du système. 28 00:01:33,110 --> 00:01:34,340 Donc pourquoi c'est intéressant tout ça? 29 00:01:34,540 --> 00:01:37,790 En fait, c'est intéressant puisqu'on va se servir de ça, 30 00:01:38,000 --> 00:01:41,870 de l'introspection et de l'intercession pour aller 31 00:01:42,070 --> 00:01:43,210 regarder à l'intérieur des objets. 32 00:01:43,490 --> 00:01:47,950 Donc ici, je définis une collection que je transforme en 33 00:01:48,150 --> 00:01:48,910 collection ordonnée. 34 00:01:49,780 --> 00:01:52,640 Et puis, je vais aller utiliser l'inspecteur de Pharo qui 35 00:01:52,840 --> 00:01:57,260 est un outil et qui va être capable de regarder à l'intérieur de cet objet. 36 00:01:58,250 --> 00:02:00,580 Donc cet objet, ça peut nous dire: c'est un objet 37 00:02:00,780 --> 00:02:03,310 instance de la classe OrderedCollection, on le voit ici. 38 00:02:03,570 --> 00:02:07,540 Cet objet, il a des variables d'instances: firstIndex, last index. 39 00:02:08,000 --> 00:02:10,350 On a des valeurs, des variables d'instances de cet objet, 40 00:02:11,110 --> 00:02:14,020 1, 12 et puis un tableau de 12 éléments. 41 00:02:14,820 --> 00:02:18,120 D'accord. Donc on peut se demander comment est-ce que cet 42 00:02:18,320 --> 00:02:21,690 outil l'inspecteur est capable d'aller regarder à l'intérieur des objets? 43 00:02:22,210 --> 00:02:24,630 Comment est-ce qu'il peut voir l'état interne des objets? 44 00:02:26,710 --> 00:02:28,950 En fait pour ça il utilise des méthodes d'introspection, 45 00:02:29,150 --> 00:02:31,160 des méthodes qui vont aller inspecter l'intérieur de l'objet. 46 00:02:31,410 --> 00:02:33,950 Donc, on en a plein qui sont définis sur la classe 47 00:02:34,150 --> 00:02:38,340 object, donc instVarAt qui permet d'aller voir une 48 00:02:38,540 --> 00:02:41,690 variable d'instance en fonction de son numéro, donc je 49 00:02:41,890 --> 00:02:44,000 veux aller voir la variable d'instance numéro 1 de cet objet-là. 50 00:02:44,720 --> 00:02:47,800 Je peux aller modifier la variable d'instance numéro 1 de 51 00:02:48,000 --> 00:02:50,310 cet objet en fixant une nouvelle valeur, ou alors je peux 52 00:02:50,510 --> 00:02:52,620 accéder à une variable d'instance par son nom ou la 53 00:02:52,820 --> 00:02:54,410 modifier par son nom: instVarNamed put. 54 00:02:54,610 --> 00:02:59,430 Donc, je vous donne des exemples. 55 00:02:59,630 --> 00:03:02,350 Donc typiquement ici, on crée un point et puis on fait 56 00:03:02,920 --> 00:03:05,450 donc le point c'est 10 3, instVarNamed X. 57 00:03:05,650 --> 00:03:10,510 Je vais récupérer la valeur de la variable d'instance qui 58 00:03:10,710 --> 00:03:13,000 s'appelle X de ce point donc ça me rend bien 10. 59 00:03:14,350 --> 00:03:19,130 Ensuite, instVarNamed X put 33, donc j'ai changé 60 00:03:19,370 --> 00:03:22,430 la valeur de la variable instance X de ce point, donc de 61 00:03:22,630 --> 00:03:25,000 10 c'est passé à 33. 62 00:03:26,000 --> 00:03:29,070 D'accord. Donc, j'ai été capable de modifier l'état 63 00:03:29,270 --> 00:03:33,090 interne d'un objet en utilisant les capacités d'introspection 64 00:03:33,500 --> 00:03:35,950 et d'intercession. Surtout l'intercession-là, instVarNamed put. 65 00:03:38,460 --> 00:03:40,910 Le gros point important c'est qu'on a violé l'encapsulation, 66 00:03:41,110 --> 00:03:42,880 c'est-à-dire que c'est un objet externe qui est venu 67 00:03:43,080 --> 00:03:45,330 modifier cet objet-là, son état interne. 68 00:03:46,140 --> 00:03:48,150 Donc ça viole complètement le principe d'encapsulation 69 00:03:48,350 --> 00:03:51,170 mais c'est extrêmement utile pour construire des outils, 70 00:03:51,600 --> 00:03:52,890 et pendant les phases de développement. 71 00:03:53,180 --> 00:03:56,250 Donc c'est à proscrire dans le code normal d'une 72 00:03:56,450 --> 00:03:59,110 application, mais par contre c'est extrêmement puissant 73 00:03:59,310 --> 00:04:01,650 pour construire des outils génériques typiquement un inspecteur de codes. 74 00:04:03,790 --> 00:04:06,830 Donc je vous donne un autre exemple de méthodes d'introspection, 75 00:04:07,030 --> 00:04:09,560 la méthode classe qui permet de récupérer la classe d'un 76 00:04:09,760 --> 00:04:11,510 objet qui est définie sur la classe objet. 77 00:04:11,710 --> 00:04:13,500 Donc, je peux demander à cette chaîne de caractères quelle est sa classe? 78 00:04:13,700 --> 00:04:16,610 Cela va me rendre à la classe Stream, ce point quelle est sa classe? 79 00:04:16,950 --> 00:04:20,040 La classe point, small top classe, je peux demander à la 80 00:04:20,240 --> 00:04:21,540 classe classe quelle est sa classe. 81 00:04:21,740 --> 00:04:23,750 ? Et puis, rajouter classe, classe. 82 00:04:24,120 --> 00:04:27,430 En gros, je peux introspecter le système en lui envoyant 83 00:04:27,630 --> 00:04:29,530 le message classe aux objets pour savoir de qui ils sont 84 00:04:29,730 --> 00:04:30,880 instances, de quelle classe ? 85 00:04:31,420 --> 00:04:33,940 On en a plein des méthodes pour introspecter le système. 86 00:04:34,310 --> 00:04:36,350 Donc ici, je prends la classe OrderedCollection puis je 87 00:04:36,550 --> 00:04:38,270 vais lui envoyer plein de messages d'introspection. 88 00:04:38,610 --> 00:04:41,300 Donc, je vais récupérer l'ensemble de ces super classes, 89 00:04:41,630 --> 00:04:44,550 tous ces sélecteurs, le nom de l'ensemble de ces 90 00:04:44,750 --> 00:04:47,110 variables d'instances, l'ensemble des sélecteurs. 91 00:04:47,820 --> 00:04:50,960 Je veux récupérer l'ensemble des noms de ses variables d'instances, 92 00:04:51,160 --> 00:04:51,920 l'ensemble de ces sous-classes. 93 00:04:52,570 --> 00:04:55,590 Et caetera. L'ensemble de ces lignes de codes. 94 00:04:57,450 --> 00:04:59,790 Donc en fait tout ça, nous permet de construire des 95 00:05:00,000 --> 00:05:04,810 outils de plus haut niveau, tel que le système navigation ici d'accord. 96 00:05:05,130 --> 00:05:08,580 Donc ce système navigation va permettre de montrer ou d'interroger 97 00:05:08,780 --> 00:05:09,620 le système au plus haut niveau. 98 00:05:09,820 --> 00:05:13,380 Donc par exemple si je veux voir l'ensemble des classes 99 00:05:13,580 --> 00:05:18,380 qui implémentent la méthode virgule. 100 00:05:19,010 --> 00:05:22,280 Ici, on voit qu'on a une fenêtre qui va s'ouvrir et puis 101 00:05:22,480 --> 00:05:25,150 on va voir tous les implémenters de virgules, donc la 102 00:05:25,350 --> 00:05:29,950 classe abstract fire reference implémente bien la méthode virgule, d'accord. 103 00:05:30,150 --> 00:05:31,950 Et j'ai la liste de toutes les classes qui implémentent cette méthode-là. 104 00:05:33,960 --> 00:05:35,050 Alors un autre exemple. 105 00:05:35,520 --> 00:05:40,350 On voudrait implémenter un menu ou 106 00:05:40,550 --> 00:05:42,940 un bouton, et pour ça quand on clique sur le bouton on 107 00:05:43,140 --> 00:05:45,480 voudrait envoyer un message à l'objet qu'il y a derrière, 108 00:05:45,770 --> 00:05:47,870 en fonction du nom du bouton par exemple. 109 00:05:49,080 --> 00:05:51,260 Comment est-ce que je peux faire pour transformer en fait 110 00:05:51,460 --> 00:05:53,800 une chaîne de caractères en message à envoyer à un objet? 111 00:05:54,690 --> 00:05:57,250 Donc voilà, j'ai une méthode d'intercession qui permet de 112 00:05:57,450 --> 00:06:00,020 faire ça, perform qui est défini sur object, donc je lui 113 00:06:00,220 --> 00:06:02,470 passe un symbole donc le nom d'un message à exécuter. 114 00:06:03,560 --> 00:06:05,880 Et puis ça va envoyer ce message-là à l'objet en question. 115 00:06:06,630 --> 00:06:10,120 Donc j'ai un deuxième typede message, donc c'est perform 116 00:06:10,320 --> 00:06:13,690 with, où je peux donner le nom du symbole, le nom de la 117 00:06:13,890 --> 00:06:16,560 méthode à exécuter, et puis passer une liste d'arguments. 118 00:06:17,060 --> 00:06:19,140 Donc je vous donne un exemple si je fais 5 factoriels, 119 00:06:19,340 --> 00:06:22,370 donc ça c'est l'envoi de message classique, et l'envoi de 120 00:06:22,570 --> 00:06:26,800 message réflexif, c'est 5 perform dièse factoriel. 121 00:06:27,000 --> 00:06:27,850 Donc là, c'est un symbole. 122 00:06:28,390 --> 00:06:32,630 Donc ça veut dire objet 5 s'il te plaît exécute ou reçoit 123 00:06:32,830 --> 00:06:34,260 le message factoriel. 124 00:06:34,460 --> 00:06:38,000 Et donc, il y a le look-up normal qui est appliqué et ces 125 00:06:38,200 --> 00:06:39,440 2 formes sont complètement équivalentes. 126 00:06:40,400 --> 00:06:42,130 Donc, je vais maintenant vous décrire un autre exemple. 127 00:06:42,330 --> 00:06:45,110 En fait ici on a un inspecteur de codes: OrderedCollection. 128 00:06:45,760 --> 00:06:48,430 On voit l'intérieur de la classe OrderedCollection. 129 00:06:49,850 --> 00:06:54,590 Donc cette classe elle contient des attributs, enfin 130 00:06:54,790 --> 00:06:55,870 des variables d'instances. 131 00:06:56,070 --> 00:07:00,380 Par exemple, methodDict, en fait, on voit que la classe 132 00:07:00,670 --> 00:07:04,420 OrderedCollection elle hérite bien de Behavior et donc 133 00:07:04,620 --> 00:07:07,010 elle a bien une methodDict ici, qui est une instance de 134 00:07:07,350 --> 00:07:09,530 dictionnaire de méthodes qui lui contient CompiledMethod. 135 00:07:10,640 --> 00:07:12,950 Et donc on voit bien ce dictionnaire des méthodes 136 00:07:13,150 --> 00:07:17,120 contient une CompiledMethod ici; et caetera, et caetera, 137 00:07:17,580 --> 00:07:18,890 une autre CompiledMethod et caetera. 138 00:07:19,090 --> 00:07:20,240 Donc qui contient plein de CompiledMethod. 139 00:07:20,930 --> 00:07:23,630 Et on va être capable pour chacune de ces CompiledMethod, 140 00:07:24,000 --> 00:07:26,750 donc ces méthodes compilées de leur demander leurs codes source. 141 00:07:27,010 --> 00:07:29,710 Si je fais self getSource, je récupère le code source de 142 00:07:29,910 --> 00:07:30,670 la méthode compilée. 143 00:07:31,000 --> 00:07:33,050 Mais on peut aller encore plus loin: une CompiledMethod 144 00:07:33,250 --> 00:07:36,430 on peut lui demander de s'exécuter directement, avec le 145 00:07:36,630 --> 00:07:39,800 message valueWithReceiver arguments, d'accord. 146 00:07:40,000 --> 00:07:42,160 Donc attention, si je fais ça il n'y a pas de lookup. 147 00:07:42,470 --> 00:07:46,710 Vu que je tiens déjà une méthode compilée, elle s'exécute 148 00:07:46,910 --> 00:07:48,380 directement, il n'y a pas d'envoi de message. 149 00:07:48,880 --> 00:07:50,600 Donc ici, je vais demander à la classe integer de 150 00:07:50,800 --> 00:07:53,570 récupérer sa CompiledMethod qui s'appelle factoriel. 151 00:07:53,850 --> 00:07:55,620 Je récupère bien une instance de la classe CompiledMethod. 152 00:07:56,440 --> 00:07:57,770 Je lui envoie le message valueWithReceiver arguments. 153 00:07:58,000 --> 00:08:01,500 Donc, je lui passe des arguments. 154 00:08:01,870 --> 00:08:03,350 Donc le receveur ça sera 5. 155 00:08:03,550 --> 00:08:05,460 Les arguments, ça sera tableau vide puisque c'est un 156 00:08:05,660 --> 00:08:08,320 message unaire, et on va bien récupérer le résultat. 157 00:08:10,070 --> 00:08:14,530 Donc, ça revient à déclencher l'exécution de la CompiledMethod sans look up. 158 00:08:15,340 --> 00:08:19,150 Donc en résumé, la réflexion c'est extrêmement puissant on l'a vu. 159 00:08:19,350 --> 00:08:23,130 C'est quelque chose qui permet d'introspecter tout le 160 00:08:23,330 --> 00:08:26,840 système, puisqu'il est représenté en lui-même sous la forme d'objets. 161 00:08:27,150 --> 00:08:29,290 Mais aussi d'aller modifier l'état du système. 162 00:08:29,690 --> 00:08:32,830 Cela permet de construire de façon générique des outils sur tous les objets. 163 00:08:34,070 --> 00:08:36,880 Donc, vous pouvez vraiment dialoguer avec les objets avec 164 00:08:37,080 --> 00:08:39,400 un protocole qui est le même pour tous les objets du 165 00:08:39,600 --> 00:08:41,870 point de vue structurel. Par contre attention, ça va 166 00:08:42,070 --> 00:08:44,810 violer les principes d'encapsulation, ce n'est pas à 167 00:08:45,010 --> 00:08:47,040 utiliser dans du code métier, c'est à utiliser pour la 168 00:08:47,240 --> 00:08:51,220 construction d'outils et ça facilite notamment l'écriture 169 00:08:51,420 --> 00:08:52,880 d'inspecteurs de code, comme on a pu le voir. 170 00:08:53,080 --> 00:08:55,800 Vous pouvez d'ailleurs aller voir comment il est implémenté en Pharo.