1 00:00:00,680 --> 00:00:02,370 Bonjour. Alors dans cette séquence, on va voir quelque 2 00:00:02,570 --> 00:00:05,700 chose d'extrêmement intéressant et important en Pharo, 3 00:00:06,130 --> 00:00:08,840 qui est le does not understand. Donc en fait j'imagine 4 00:00:09,040 --> 00:00:10,870 que vous avez déjà eu des débuggers qui sont ouverts avec 5 00:00:11,870 --> 00:00:12,910 la méthode doesNotUnderstand affichée. 6 00:00:14,010 --> 00:00:16,460 Donc on va voir d'où elle vient et à quoi elle sert. 7 00:00:17,330 --> 00:00:19,040 Donc on va prendre un exemple, ici. 8 00:00:19,240 --> 00:00:20,000 Donc je vais vous l'expliquer. 9 00:00:20,370 --> 00:00:21,620 On a un objet ici, node1. 10 00:00:21,820 --> 00:00:26,000 Cet objet on va lui envoyer le message Coucou Stef. 11 00:00:26,170 --> 00:00:27,370 Donc ici, c'est le symbole Steph. 12 00:00:28,340 --> 00:00:32,360 Donc node1, si vous reprenez le lookup, on va remonter à 13 00:00:32,560 --> 00:00:33,810 la classe de cet objet. 14 00:00:34,230 --> 00:00:37,220 Est-ce qu'il existe une méthode coucou sur cette classe? 15 00:00:37,420 --> 00:00:39,300 Non. Alors on va remonter à la super classe. 16 00:00:39,500 --> 00:00:41,870 Est-ce qu'il existe une méthode coucou dans la face object? 17 00:00:42,070 --> 00:00:44,820 Non. Alors que va faire la machine virtuelle? 18 00:00:45,060 --> 00:00:47,170 Elle va dire: je n'ai pas trouvé de méthode 19 00:00:47,370 --> 00:00:49,420 correspondant à l'envoi de messages effectués sur l'objet 20 00:00:49,620 --> 00:00:50,950 donc je fais réifier le message. 21 00:00:51,240 --> 00:00:55,480 Donc réifier, j'en ai déjà parlé dans la séquence sur l'introspection, 22 00:00:55,680 --> 00:00:57,880 sur la réflexion. Donc l'idée de réifier, c'est de 23 00:00:58,080 --> 00:01:01,310 représenter sous la forme d'un objet, un concept qui 24 00:01:01,510 --> 00:01:04,580 normalement est implicite, donc en l'occurrence ici le message. 25 00:01:05,000 --> 00:01:07,640 Donc ici, on va créer un objet pour représenter le message Coucou Stef. 26 00:01:08,060 --> 00:01:10,000 Donc c'est une instance de la classe message en Pharo. 27 00:01:10,620 --> 00:01:12,210 Et puis la machine virtuelle, ce qu'elle va faire, c'est 28 00:01:12,410 --> 00:01:15,010 qu'elle va réenvoyer, elle va refaire un envoi de message 29 00:01:15,230 --> 00:01:18,540 à cet objet node1 ici, sauf qu'elle va lui envoyer le 30 00:01:18,740 --> 00:01:22,560 message doesNotUnderstand, et lui passer cet objet message en paramètre. 31 00:01:22,940 --> 00:01:26,440 Donc il y a une nouvelle exécution de l'algorithme de lookup. 32 00:01:26,640 --> 00:01:29,240 Cette fois, la machine virtuelle va chercher est-ce qu'il 33 00:01:29,440 --> 00:01:31,870 existe la méthode doesNotUnderstand dans la classe Node? 34 00:01:32,070 --> 00:01:33,510 Non. Alors elle remonte. 35 00:01:33,910 --> 00:01:35,250 Donc on remonte dans la super classe. 36 00:01:35,450 --> 00:01:37,300 Est-ce qu'il existe une méthode doesNotUnderstand dans la classe objet? 37 00:01:37,500 --> 00:01:40,000 Oui, elle est là. Donc là, elle est sous forme abrégée 38 00:01:40,200 --> 00:01:42,760 dnu, mais c'est la méthode doesNotUnderstand, donc elle 39 00:01:43,000 --> 00:01:44,310 va pouvoir être exécutée. 40 00:01:47,170 --> 00:01:48,470 Donc ce qu'il faut bien comprendre, c'est que 41 00:01:48,670 --> 00:01:50,950 doesNotUnderstand c'est un message qu'on va envoyer aux 42 00:01:51,150 --> 00:01:53,030 objets, que la machine virtuelle va envoyer aux objets 43 00:01:53,230 --> 00:01:56,050 pour vous, quand un envoi de message a échoué. 44 00:01:57,120 --> 00:01:59,830 Donc toutes les classes peuvent redéfinir cette méthode 45 00:02:00,030 --> 00:02:03,630 doesNotUnderstand, pour vraiment avoir son propre 46 00:02:03,830 --> 00:02:06,810 comportement quand un message n'est pas compris par l'une de ces instances. 47 00:02:07,440 --> 00:02:09,580 Donc c'est vraiment important, ça permet de construire 48 00:02:10,280 --> 00:02:12,280 énormément de choses grâce à cette méthode 49 00:02:12,480 --> 00:02:14,500 doesNotUnderstand, grâce à ce hook. Donc ça permet de 50 00:02:14,700 --> 00:02:17,850 construire de la délégation automatique, c'est utilisé 51 00:02:18,260 --> 00:02:20,410 aussi dans la programmation distribuée et caetera. 52 00:02:21,280 --> 00:02:23,020 Donc nous, on va voir quelques usages possibles du 53 00:02:23,220 --> 00:02:25,030 doesNotUnderstand dans cette séquence. 54 00:02:25,710 --> 00:02:27,250 Donc l'idée, par exemple, imaginons que je veuille 55 00:02:27,450 --> 00:02:30,320 rediriger tous les messages reçus par un objet vers un autre. 56 00:02:31,150 --> 00:02:32,700 Donc la délégation simple. 57 00:02:33,120 --> 00:02:35,450 Donc pour ça, je vais construire un objet Delegating, 58 00:02:35,650 --> 00:02:38,190 donc qui va stocker la cible, vers quel objet je dois 59 00:02:38,390 --> 00:02:41,000 renvoyer tous les messages. Je vais redéfinir la méthode doesNotUnderstand. 60 00:02:41,780 --> 00:02:43,800 Je vous l'ai dit, en paramètres elle prend un objet 61 00:02:44,170 --> 00:02:47,020 message qui va contenir le sélecteur du message qui n'avait 62 00:02:47,220 --> 00:02:49,180 pas été compris, ainsi que la liste des arguments. 63 00:02:49,660 --> 00:02:54,030 Et puis je peux demander à ce message de se rediriger, d'être 64 00:02:54,230 --> 00:02:58,870 réenvoyé, donc je vais utiliser sendTo self target, qui 65 00:02:59,070 --> 00:03:00,020 est bien la variable d'instance. 66 00:03:00,800 --> 00:03:03,040 Donc je vais réenvoyer ce message à un autre objet. 67 00:03:04,350 --> 00:03:06,700 Donc attention, cette pratique c'est extrêmement 68 00:03:06,900 --> 00:03:10,450 puissant, mais également ça nuit un petit peu à la 69 00:03:11,060 --> 00:03:12,100 lisibilité du code. 70 00:03:12,710 --> 00:03:17,490 Vous l'avez ici. Il faut vraiment aller lire le code pour 71 00:03:17,690 --> 00:03:19,930 savoir qui est-ce qui va recevoir le message in fine. 72 00:03:20,940 --> 00:03:22,810 Par contre, c'est extrêmement pratique pour la 73 00:03:23,010 --> 00:03:25,480 construction d'outils ou la construction de mécanismes un 74 00:03:25,680 --> 00:03:29,910 peu avancés, comme je vous l'ai dit précédemment. 75 00:03:30,110 --> 00:03:33,050 Donc on va voir un autre exemple ensemble, le loggingProxy. 76 00:03:34,170 --> 00:03:38,440 L'idée de base c'est de créer un objet minimal qui va 77 00:03:38,640 --> 00:03:42,470 contenir très peu de méthode, de customiser, de redéfinir 78 00:03:42,670 --> 00:03:46,900 sa méthode doesNotUnderstand. Et puis ensuite, ce qu'on 79 00:03:47,100 --> 00:03:50,230 va faire, c'est qu'on va échanger un objet métier grâce à 80 00:03:50,430 --> 00:03:52,250 become avec cet objet minimal, ce proxy. 81 00:03:54,900 --> 00:03:58,770 Donc voilà comment on va faire, je crée un objet proxy. 82 00:03:59,360 --> 00:04:02,800 Donc cet objet proxy, je vais mettre un sujet. 83 00:04:03,080 --> 00:04:05,670 Donc le sujet, c'est l'objet que je vais remplacer, donc 84 00:04:05,870 --> 00:04:08,070 la cible, la target. 85 00:04:08,860 --> 00:04:12,080 Et puis je vais, par exemple, mettre un Counter d'invocation. 86 00:04:12,280 --> 00:04:16,360 Donc à chaque fois qu'un message va être reçu, on va incrémenter le Counter. 87 00:04:16,560 --> 00:04:18,250 Dans initialize, je vais mettre à 0. 88 00:04:18,450 --> 00:04:20,110 Le Counter d'invocation, pour l'instant, n'a reçu aucun 89 00:04:20,310 --> 00:04:25,090 message et puis le sujet qui est-ce qu'on va remplacer. 90 00:04:26,520 --> 00:04:28,140 Maintenant on va redéfinir la méthode doesNotUnderstand 91 00:04:28,340 --> 00:04:31,300 sur ce proxy, donc on va dire à chaque fois qu'il reçoit 92 00:04:31,500 --> 00:04:34,550 un message qu'il ne comprend pas il va afficher sur le 93 00:04:34,750 --> 00:04:35,710 transcript qu'il a reçu un message. 94 00:04:35,930 --> 00:04:38,290 Il va incrémenter son counter, j'ai reçu un nouveau 95 00:04:38,490 --> 00:04:41,660 message, un de plus et puis je vais transférer le message 96 00:04:41,860 --> 00:04:46,650 à mon sujet. Donc comme précédemment, je transfère le 97 00:04:46,850 --> 00:04:49,200 message à quelqu'un d'autre. 98 00:04:49,400 --> 00:04:51,610 Donc pour le sendTo, si vous regardez l'implémentation 99 00:04:51,810 --> 00:04:54,580 dans la classe Message c'est tout bête, on avait déjà vu, 100 00:04:54,870 --> 00:04:57,000 c'est la méthode perform withArguments. 101 00:04:57,650 --> 00:05:00,530 On en avait déjà parlé dans une séquence précédente, donc 102 00:05:00,730 --> 00:05:01,490 là il n'y a rien de nouveau. 103 00:05:03,020 --> 00:05:07,890 Voyons maintenant un exemple, comment est-ce qu'on peut 104 00:05:08,090 --> 00:05:09,010 utiliser ce loggingProxy. 105 00:05:10,020 --> 00:05:14,690 Donc on va créer une instance, un objet point, et puis je 106 00:05:14,890 --> 00:05:18,280 vais utiliser maintenant become pour dire: tous ceux qui 107 00:05:18,480 --> 00:05:22,350 pointent sur ce point, ils vont pointer sans s'en rendre 108 00:05:22,550 --> 00:05:27,140 compte sur un loggingProxy, que j'ai instancié. 109 00:05:27,340 --> 00:05:30,500 Et maintenant, si j'envoie des messages à l'objet point, 110 00:05:31,000 --> 00:05:33,090 donc attention on intègre maintenant l'objet point vu qu'il 111 00:05:33,290 --> 00:05:36,000 y a eu become, c'est devenu l'instance du loggingProxy. 112 00:05:36,930 --> 00:05:39,030 Donc à chaque fois que je lui envoie un message, 113 00:05:39,940 --> 00:05:41,900 forcément ça va s'afficher sur le transcript. 114 00:05:42,720 --> 00:05:45,190 Et puis le Counter d'invocations va être incrémenté. 115 00:05:46,000 --> 00:05:48,280 Vous vous souvenez, dans le doesNotUnderstand c'est ce qu'on faisait. 116 00:05:49,050 --> 00:05:53,090 Donc on peut voir qu'à la fin, le Counter invocations, il vaut bien 3. 117 00:05:54,480 --> 00:05:56,260 Donc il y a quelques limites, par exemple dans le petit 118 00:05:56,460 --> 00:06:00,620 framework de proxy, exemple que je viens de présenter, il 119 00:06:00,820 --> 00:06:04,320 y a des limites, on ne peut pas forcément capturer par 120 00:06:04,520 --> 00:06:07,050 exemple les messages qu'un objet s'envoie à lui-même, ça va être difficile. 121 00:06:07,250 --> 00:06:10,430 On ne peut pas utiliser un become sur des classes, donc 122 00:06:10,630 --> 00:06:14,100 les opérations réflexives ont des limites en Pharo. 123 00:06:15,060 --> 00:06:17,290 Par exemple, ce qui va être compliqué aussi, imaginons 124 00:06:17,490 --> 00:06:21,210 que l'objet à remplacer et le proxy comprennent tous les 2 le même message. 125 00:06:21,760 --> 00:06:23,820 Ce qui fait que quand je vais envoyer le message au 126 00:06:24,020 --> 00:06:27,530 proxy, il va répondre à la place de le capturer avec un 127 00:06:27,730 --> 00:06:31,420 doesNotUnderstand, et de le transférer à son objet cible. 128 00:06:32,310 --> 00:06:34,800 Donc, il y a d'autres frameworks de proxy, plus puissants 129 00:06:35,000 --> 00:06:36,550 qui existent en Pharo, qui permettent de vraiment tout 130 00:06:36,750 --> 00:06:41,000 capturer, mais ils sont plus importants qu'un exemple 131 00:06:41,200 --> 00:06:41,960 aussi petit que celui-là. 132 00:06:42,800 --> 00:06:45,800 Donc une autre application, un autre exemple d'utilisation 133 00:06:46,000 --> 00:06:47,950 de cette technique, ça peut être par exemple la 134 00:06:48,150 --> 00:06:52,050 génération des accesseurs ou même des méthodes 135 00:06:52,540 --> 00:06:56,080 dynamiquement. Par exemple, imaginons ici toujours 136 00:06:56,280 --> 00:06:59,380 définie la méthode doesNotUnderstand et puis je vais dire 137 00:06:59,580 --> 00:07:01,750 : OK, il y a un message qui a été reçu donc je vais 138 00:07:01,950 --> 00:07:06,250 tester est-ce que j'ai des variables d'instances qui incluent ce message? 139 00:07:06,450 --> 00:07:09,940 Si oui, alors je vais générer une nouvelle méthode donc 140 00:07:10,140 --> 00:07:12,570 je vais utiliser compile pour générer une nouvelle 141 00:07:12,770 --> 00:07:17,160 méthode sur la classe, qui va répondre 142 00:07:17,360 --> 00:07:19,490 directement la valeur de cette variable. 143 00:07:19,690 --> 00:07:23,450 Donc je suis en train de générer l'accesseur en lecture d'une variable. 144 00:07:24,140 --> 00:07:27,420 Et puis si vraiment si le message qui a été envoyé ne 145 00:07:27,620 --> 00:07:31,380 correspond pas à un nom d'une variable d'instances, je 146 00:07:31,580 --> 00:07:33,710 fais un super doesNotUnderstand. Donc ça va nous 147 00:07:33,910 --> 00:07:37,170 permettre d'automatiquement remplir les accesseurs en 148 00:07:37,370 --> 00:07:41,440 lecture, en fonction du fait qu'ils ont été appelés ou pas sur un objet. 149 00:07:42,750 --> 00:07:45,620 Donc en conclusion dans cette séquence, on peut voir qu'on 150 00:07:45,820 --> 00:07:48,000 va être capables d'utiliser des objets minimaux. 151 00:07:48,180 --> 00:07:49,910 Donc on a vu que ce n'était pas des objets qui étaient 152 00:07:50,110 --> 00:07:52,040 directement instance de la classe Object mais de la 153 00:07:52,240 --> 00:07:54,200 classe proto object, donc c'est vraiment des tout petits objets. 154 00:07:54,400 --> 00:07:56,770 Ça peut être la base pour des frameworks de proxy. 155 00:07:57,440 --> 00:07:59,070 Grâce à la redéfinition de la méthode doesNotUnderstand, 156 00:07:59,270 --> 00:08:03,180 on va être capable de capturer le fait qu'il y a un envoi 157 00:08:03,380 --> 00:08:04,790 de message qui a raté, et on va pouvoir avoir un 158 00:08:05,000 --> 00:08:06,900 comportement, rediriger ce message ailleurs et avoir un 159 00:08:07,100 --> 00:08:07,870 traitement spécifique. 160 00:08:08,320 --> 00:08:11,380 Donc c'est un hook qui est extrêmement puissant, qui est 161 00:08:11,580 --> 00:08:13,460 à la base de beaucoup d'outils en Pharo. 162 00:08:15,190 --> 00:08:17,080 Et par contre, il faut faire attention, il faut vraiment 163 00:08:17,280 --> 00:08:20,470 l'utiliser que quand c'est réellement nécessaire, quand 164 00:08:20,670 --> 00:08:23,550 vraiment on en a un besoin. Donc ne mettez pas ça dans du 165 00:08:23,750 --> 00:08:26,750 code métier, encore ça reste une technique avancée de Pharo.