1 00:00:00,480 --> 00:00:04,600 Este video se enfocará en un aspecto avanzado de Pharo, 2 00:00:04,800 --> 00:00:10,800 que son las operaciones reflexivas necesarias para la programación en vivo que usamos. 3 00:00:11,680 --> 00:00:16,680 Analizaremos lo que sucede cuando recompilamos una clase. 4 00:00:17,040 --> 00:00:20,080 Y explicaremos las operaciones reflexivas 5 00:00:20,200 --> 00:00:24,720 necesarias para implementar programación en vivo. 6 00:00:24,920 --> 00:00:26,560 Este es un caso típico. 7 00:00:26,720 --> 00:00:30,320 Por lo general, comenzamos por definir una clase, 8 00:00:30,600 --> 00:00:34,640 luego agregamos métodos y creamos instancias de esa clase. 9 00:00:35,160 --> 00:00:40,400 Luego redefinimos la clase y agregamos nuevas variables de instancia. 10 00:00:41,200 --> 00:00:45,640 Entonces, ¿qué hacemos con las instancias que ya existían 11 00:00:46,160 --> 00:00:48,440 cuando hay una variable de instancia menos? 12 00:00:48,680 --> 00:00:53,920 Debemos configurar un mecanismo para migrar estas instancias 13 00:00:54,280 --> 00:00:57,360 a la nueva versión de la clase. 14 00:00:57,640 --> 00:00:59,160 Luego seguimos trabajando. 15 00:00:59,600 --> 00:01:03,200 Después de eso, veremos las operaciones 16 00:01:04,440 --> 00:01:09,160 que habilitan la redefinición dinámica de clases, recompilación de métodos, 17 00:01:09,600 --> 00:01:11,040 y que permiten 18 00:01:11,400 --> 00:01:15,160 una migración de instancias automática y transparente 19 00:01:15,360 --> 00:01:18,200 a la nueva versión de la clase. 20 00:01:18,520 --> 00:01:22,560 Para hacer esto, necesitamos recopilar todas las instancias de clase. 21 00:01:22,840 --> 00:01:28,280 Entonces tenemos que cambiar todo lo que usaba estos objetos 22 00:01:28,840 --> 00:01:31,920 y asignar sus punteros a nuevos objetos. 23 00:01:32,400 --> 00:01:33,400 ¿Vamos? 24 00:01:34,160 --> 00:01:38,920 Primero, ¿cómo recopilamos todas las instancias de una clase? 25 00:01:39,400 --> 00:01:43,560 Si enviamos el mensaje allInstances a una clase, 26 00:01:43,800 --> 00:01:47,320 muestra todos los objetos que son sus instancias. 27 00:01:47,640 --> 00:01:51,440 Es una coleccion de todos los objetos estándar. 28 00:01:51,640 --> 00:01:57,800 Si lo enviamos a la clase de Window, obtenemos una colección de objetos de ventana. 29 00:01:58,280 --> 00:02:02,760 Podemos recuperar el primer elemento y envíarle un mensaje "close" 30 00:02:02,920 --> 00:02:06,840 ya que el método "close" se define en la clase Window. 31 00:02:07,360 --> 00:02:11,840 Otra primitiva reflexiva es "pointersTo". 32 00:02:12,160 --> 00:02:16,920 Si enviamos este mensaje a un objeto, accedemos a la colección 33 00:02:17,400 --> 00:02:21,000 de todos los objetos que almacenan una referencia al mismo. 34 00:02:21,200 --> 00:02:23,040 Esto es muy útil 35 00:02:23,200 --> 00:02:27,320 cuando queremos intercambiar objetos. 36 00:02:29,560 --> 00:02:34,080 La primitiva para intercambiar punteros es "become". 37 00:02:34,600 --> 00:02:39,760 La idea es habilitarnos para intercambiar dos objetos. 38 00:02:41,160 --> 00:02:43,840 Queremos intercambiarlos simétricamente. 39 00:02:44,200 --> 00:02:48,200 Todo lo que apuntaba a este objeto en el sistema, 40 00:02:48,720 --> 00:02:51,160 en este caso tenemos dos punteros, 41 00:02:51,360 --> 00:02:55,840 Se invertirá para que los elementos ahora apunta a este objeto. 42 00:02:57,280 --> 00:03:01,720 Rompemos los enlaces para los punteros que estaban de este lado, 43 00:03:02,280 --> 00:03:04,080 por lo que cambian de objeto. 44 00:03:06,360 --> 00:03:11,680 "Become" significa invertir todos los punteros en el sistema simétricamente. 45 00:03:13,280 --> 00:03:15,080 Aquí hay un ejemplo. 46 00:03:15,320 --> 00:03:17,600 Yo creo un pt1, 47 00:03:17,800 --> 00:03:22,320 que apunta al objeto "0 @ 0" y una variable pt2, 48 00:03:22,840 --> 00:03:25,320 que también apunta al objeto "0 @ 0". 49 00:03:25,560 --> 00:03:29,560 Además de una variable pt3 que apunta al punto "100 @ 100". 50 00:03:29,800 --> 00:03:33,200 Entonces escribo la primitiva "pt1 become: pt3". 51 00:03:34,160 --> 00:03:38,680 Todo lo que apuntaba al objeto denotado por la variable pt1 52 00:03:38,920 --> 00:03:41,440 ahora apuntará al punto 3. 53 00:03:42,200 --> 00:03:44,400 Es decir, todos los punteros a pt1. 54 00:03:44,600 --> 00:03:49,760 Vemos que la variable pt2 apunta al mismo objeto que pt1, 55 00:03:49,920 --> 00:03:54,400 y ahora apunta a lo que fue referenciado por pt3. 56 00:03:54,760 --> 00:04:00,440 En cuanto a pt3, ya que es simétrico, apuntará a lo que apuntó pt1. 57 00:04:00,640 --> 00:04:01,760 Hasta arriba 58 00:04:02,800 --> 00:04:06,080 Y pt1 apunta a lo que apuntó pt3. 59 00:04:06,280 --> 00:04:10,000 Los punteros han sido intercambiados simétricamente. 60 00:04:11,200 --> 00:04:14,800 La variante asimétrica es "becomeForward". 61 00:04:15,440 --> 00:04:18,400 Esto indica que queremos intercambiar punteros. 62 00:04:18,640 --> 00:04:23,360 Todo lo que apuntaba a este objeto se pasará a ese objeto. 63 00:04:24,080 --> 00:04:28,400 Pero no al contrario. Los punteros a este objeto permanecen iguales. 64 00:04:31,520 --> 00:04:34,640 Aquí hay otro ejemplo usando puntos. 65 00:04:35,280 --> 00:04:39,640 Cuando ejecutamos un "becomeForward", 66 00:04:39,920 --> 00:04:45,080 vemos que impacta en pt1 y pt2. 67 00:04:45,600 --> 00:04:48,640 pt3 no se vio afectado por el "becomeForward", 68 00:04:48,840 --> 00:04:53,000 y los que apuntaban a este objeto no se modifican. 69 00:04:55,400 --> 00:04:59,840 Otra primitiva reflexiva es "adoptInstance". 70 00:05:00,200 --> 00:05:02,640 Esto cambia la clase de un objeto. 71 00:05:02,840 --> 00:05:07,920 Le pedimos a una clase que adopte una nueva instancia, pasada como un parámetro. 72 00:05:08,560 --> 00:05:13,400 Cambiar una clase es herramienta muy poderosa, pero algo limitada. 73 00:05:13,640 --> 00:05:17,520 Es esencial que la clase original del objeto 74 00:05:18,160 --> 00:05:19,840 en este caso, "anInstance", 75 00:05:20,040 --> 00:05:24,680 sea compatible con el formato de la clase objetivo. 76 00:05:25,440 --> 00:05:29,160 No puedes simplemente intercambiar cualquier objeto. 77 00:05:29,360 --> 00:05:31,840 A veces está indexado, etcétera. 78 00:05:32,080 --> 00:05:36,000 El formato de un objeto es muy importante. 79 00:05:36,680 --> 00:05:40,640 Miremos que es una clase en esencia. 80 00:05:40,920 --> 00:05:43,360 Una clase es esencialmente un formato. 81 00:05:43,640 --> 00:05:47,200 Un formato especifica el número de variables de instancia 82 00:05:47,400 --> 00:05:52,520 y el tipo de variables, como explicamos en un curso anterior. 83 00:05:52,840 --> 00:05:56,000 Tiene una superclase y un diccionario de métodos. 84 00:05:56,840 --> 00:06:01,680 Aquí tenemos "Behavior class", que es una superclase 85 00:06:02,080 --> 00:06:07,520 de "Class class", que define el comportamiento básico de las clases. 86 00:06:08,160 --> 00:06:11,000 Es el mínimo básico para una clase. 87 00:06:11,200 --> 00:06:14,720 Entonces, una clase tiene una superclase, un diccionario de métodos, 88 00:06:14,840 --> 00:06:18,200 y especificaciones de formato. 89 00:06:19,200 --> 00:06:24,440 Ahora resumiré todas las características de comportamiento reflexivo 90 00:06:25,000 --> 00:06:27,360 que hemos discutido hasta ahora, 91 00:06:28,440 --> 00:06:33,440 que dan ciertas instancias comportamiento que es específico de ellas. 92 00:06:34,760 --> 00:06:37,800 Explicaré el código a medida que avancemos. 93 00:06:38,000 --> 00:06:42,400 Vamos a crear una instancia de la "Behavior class" en estas tres líneas. 94 00:06:42,640 --> 00:06:44,280 Recuerda, es una clase. 95 00:06:44,640 --> 00:06:50,080 Creo una instancia de la clase, que yo llamo Behavior. 96 00:06:51,600 --> 00:06:54,400 Eso me da un objeto llamado Behavior. 97 00:06:55,040 --> 00:07:00,600 Indico que este objeto hereda de la clase Model. 98 00:07:02,000 --> 00:07:03,000 Como esto. 99 00:07:03,680 --> 00:07:08,080 Configuro el formato de este objeto Behavior. 100 00:07:08,600 --> 00:07:12,400 Entonces creo una instancia de la clase Model. 101 00:07:14,520 --> 00:07:16,360 Es un objeto llamado Model. 102 00:07:17,200 --> 00:07:20,080 Aquí está la línea importante en este código. 103 00:07:20,760 --> 00:07:23,920 Cambiaré la clase de este objeto Model 104 00:07:24,080 --> 00:07:28,920 para convertirse en una clase del objeto pasado como un parámetro, llamado Behavior. 105 00:07:29,200 --> 00:07:34,400 Rompo el enlace y lo hago una instancia de esta clase. 106 00:07:34,800 --> 00:07:37,400 Esta es una subclase de la clase Model. 107 00:07:38,800 --> 00:07:43,400 Ahora puedo compilar Un nuevo método en esta clase. 108 00:07:43,600 --> 00:07:47,400 Compilo el método #foo, que devuelve 2 109 00:07:48,840 --> 00:07:51,840 Estoy haciendo esto en el objeto Behavior. 110 00:07:53,560 --> 00:07:55,280 Como podemos ver aquí, 111 00:07:55,560 --> 00:07:59,840 si envío el mensaje foo al objeto Model, 112 00:08:01,000 --> 00:08:02,160 como aquí, 113 00:08:02,760 --> 00:08:04,160 regresará 2. 114 00:08:04,640 --> 00:08:06,720 Esto sigue el método de búsqueda. 115 00:08:07,400 --> 00:08:09,040 Envío el mensaje foo. 116 00:08:09,200 --> 00:08:14,600 El objeto Model busca el método en su clase, el objeto Behavior, 117 00:08:14,800 --> 00:08:17,360 y encuentra con éxito el método. 118 00:08:17,760 --> 00:08:19,160 Funciona a la perfección. 119 00:08:19,920 --> 00:08:24,080 Pero si creo una nueva instancia de clase Model, 120 00:08:25,200 --> 00:08:26,200 como esta, 121 00:08:26,560 --> 00:08:28,360 y le envío el mensaje foo, 122 00:08:29,360 --> 00:08:33,360 se indica un error via MessageNotUnderstood. 123 00:08:33,640 --> 00:08:35,800 Porque si aplico ToLookUp, 124 00:08:36,080 --> 00:08:39,080 miro en la clase del objeto, Model class, 125 00:08:39,320 --> 00:08:43,920 pero no encuentro el método foo en su diccionario o superclases. 126 00:08:45,040 --> 00:08:51,040 Este mecanismo avanzado nos permite dotar a una instancia específica 127 00:08:51,520 --> 00:08:54,040 de la clase Model con un comportamiento. 128 00:08:54,200 --> 00:08:57,840 Aplicemos esto a la clase Set para aclararlo. 129 00:08:58,040 --> 00:09:01,280 Creo set1, una instancia de la clase Set. 130 00:09:01,800 --> 00:09:05,720 El diccionario de método de clase Set contiene el método add:. 131 00:09:06,400 --> 00:09:11,520 Para una instancia específica de la clase Set, Quiero cambiar el método add:, 132 00:09:11,720 --> 00:09:15,360 que tiene un comportamiento específico para un conjunto específico. 133 00:09:15,520 --> 00:09:18,400 Entonces, creo una clase "anónima" aquí. 134 00:09:18,840 --> 00:09:22,920 Es una clase específica que hereda. de la clase Set. 135 00:09:23,280 --> 00:09:25,200 Aquí está su herencia. 136 00:09:25,600 --> 00:09:31,160 El objeto set2 es una instancia de esta clase "anónima". 137 00:09:31,720 --> 00:09:37,000 En su diccionario de métodos, Redefiniré el método add: 138 00:09:37,320 --> 00:09:40,640 dándole un comportamiento particular. 139 00:09:40,920 --> 00:09:45,800 Ahora, si envío el mensaje add: al objeto set2, 140 00:09:46,080 --> 00:09:48,400 este método será seleccionado, 141 00:09:48,800 --> 00:09:52,320 y tendrá un comportamient específico, diferente 142 00:09:53,600 --> 00:09:58,040 del método add: aquí si hubiéramos enviado el mensaje a este conjunto. 143 00:09:58,280 --> 00:10:03,360 Entonces, tenemos dos conjuntos que reaccionan De manera diferente al mensaje add:. 144 00:10:03,680 --> 00:10:07,080 Aquí está el código para llevar a cabo este ejercicio. 145 00:10:07,400 --> 00:10:11,280 Al igual que antes, creo una clase 146 00:10:11,640 --> 00:10:13,800 como una instancia de "Behavior class". 147 00:10:14,080 --> 00:10:16,840 Establezco la superclase como "Set class". 148 00:10:17,400 --> 00:10:18,640 Configuro el formato. 149 00:10:18,840 --> 00:10:23,600 Compilo el método add: en esta clase anónima. 150 00:10:24,080 --> 00:10:29,360 Estoy redefiniendo el método add: que está define en la clase Set. 151 00:10:30,080 --> 00:10:36,080 Uso "Transcript show" para mostrar la ejecución del método add:. 152 00:10:36,400 --> 00:10:40,680 Entonces llamo "super" para ejecutar el método add: en la clase Set. 153 00:10:41,360 --> 00:10:45,720 Ahora probaremos este código. creando un primer set. 154 00:10:45,920 --> 00:10:48,600 Aquí tengo la clase Set. 155 00:10:50,280 --> 00:10:54,280 Creo la primera instancia de esta clase, llamada Set. 156 00:10:55,080 --> 00:10:57,040 Le envío el mensaje add:. 157 00:10:58,920 --> 00:11:03,760 Envío add:1, que usa el método agregar:de la clase Set. 158 00:11:05,240 --> 00:11:08,720 Si pido la clase Set aquí, Voy a tener Set. 159 00:11:09,400 --> 00:11:13,160 Pero ahora ejecutaré este primitiva que ves aquí. 160 00:11:13,600 --> 00:11:16,200 Le pido al objeto Set que cambie las clases. 161 00:11:16,400 --> 00:11:21,160 para usar la clase Behavior de antes, que es una subclase 162 00:11:22,080 --> 00:11:23,760 de la clase Set. 163 00:11:24,360 --> 00:11:28,400 Entonces, cambia y se vuelve una instancia de la clase Set, 164 00:11:28,680 --> 00:11:32,000 que tiene una nueva versión del método add:. 165 00:11:32,280 --> 00:11:37,920 Ahora, si envío el mensaje add: 2 a este objeto, 166 00:11:38,360 --> 00:11:43,280 seleccionará el método add: desde el objeto Behavior, 167 00:11:43,560 --> 00:11:45,720 y ejecutará este código. 168 00:11:46,280 --> 00:11:48,920 Podemos verificar en el Transcript 169 00:11:49,760 --> 00:11:53,280 si el método se ha ejecutado. 170 00:11:53,640 --> 00:11:57,400 Eventualmente se ejecutará, 171 00:11:57,640 --> 00:12:02,040 ya que también usamos "super" para el método add: de la clase Set. 172 00:12:02,840 --> 00:12:07,840 Esto nos permite espiar en instancias seleccionadas de Set, 173 00:12:08,080 --> 00:12:09,560 usando esta línea aquí. 174 00:12:11,200 --> 00:12:12,400 Para concluir, 175 00:12:12,600 --> 00:12:19,200 todas estas operaciones reflexivas nos permiten crear herramientas muy innovadoras. 176 00:12:19,440 --> 00:12:23,840 Podemos probar e implementar nuevas funciones 177 00:12:24,080 --> 00:12:29,400 gracias a estas primitivas reflexivas, que promueven la extensibilidad del lenguaje. 178 00:12:30,200 --> 00:12:34,080 Pero hay una regla de oro cuando se usa la reflexión. 179 00:12:34,320 --> 00:12:38,800 No hay que usarlo de manera inapropiada. en el código de dominio. 180 00:12:39,040 --> 00:12:44,720 Limitamos el uso de códigos reflexivo en el código de dominio. 181 00:12:45,080 --> 00:12:49,200 La reflexión puede violar el encapsulamiento de los objetos. 182 00:12:49,840 --> 00:12:51,000 Realmente puede ... 183 00:12:51,440 --> 00:12:54,640 Puede sobrepasar reglas de programación de objetos, 184 00:12:54,840 --> 00:12:58,520 y por lo tanto está reservado para la construcción de herramientas.