martes, agosto 09, 2005

La magia del Smalltalk: Capítulo 8 - Algo útil con el #become:

Ya es hora de desvelar algo del misterio que existe detrás del #become:.

Para comenzar, veamos que pasó con el "ejemplo" anterior:

| s1 s2 |

s1 := 'Un String'.
s2 := 'Un String'.

s1 become: 'Otro String'.

Transcript show: s1; cr.
Transcript show: s2; cr.

Lo que ocurre es muy simple: El compilador crea, en la tabla de símbolos del método, un sólo objeto 'Un String'. Ambas variables (s1 y s2) apuntan al mismo objeto, para probar lo que digo evalúen:

| s1 s2 |

s1 := 'Un String'.
s2 := 'Un String'.

Transcript show: (s1 == s2); cr.

Al hacer #become: entre el objeto 'Un String' y el objeto 'Otro String' todas las referencias al objeto 'Un String' (en este caso las variables s1 y s2) se actualizan.

Este ejemplo (creo que) muestra todo lo relativo al become:

| s1 s2 s3 |

s1 := Date today.
s2 := s1.
s3 := 'Un String'.

Transcript show: '----- pre-become: -----'; cr.
Transcript show: s1; cr.
Transcript show: s2; cr.
Transcript show: s3; cr.
Transcript show: s1 == s2; cr.
Transcript show: s1 == s3; cr.

s1 become: s3.

Transcript show: '----- post-become: -----'; cr.
Transcript show: s1; cr.
Transcript show: s2; cr.
Transcript show: s3; cr.
Transcript show: s1 == s2; cr.
Transcript show: s1 == s3; cr.



Ahora veamos algunos buenos ejemplos de uso del #become:.

¿Recuerdan el proxy que hicimos en el Capítulo 1?

Los proxies, ya sea que se hagan con #doesNotUnderstand: o de la forma tradicional, son un recurso muy útil pero tienen algunas contras. Una de ellas es la penalidad en performance que implica que cada envío de mensaje pasa a través del proxy generando, al menos, un envío de mensaje más.

Una solución, muy al estilo de Smalltalk, es hacer un proxy que capture los mensajes con un #doesNotUnderstand: tal cual lo vimos en el Capítulo 1. Con esa implementación hacemos un #become: que reemplace el proxy con el receptor en cuanto podamos. Eso sería algo así:

Proxy>>doesNotUnderstand: aMessage
   "load the proxied object, switch the receiver with it and routes the incoming message"

   | proxyThenProxied proxiedThenProxy |

   proxyThenProxied := self.

   "Lazy load of proxied object"
   proxiedThenProxy := self loadProxied.

   proxyThenProxied become: proxiedThenProxy.

   ^ proxyThenProxied
      perform: aMessage selector
      withArguments: aMessage arguments

Un proxy como este paga el costo de hacer un #become: con el primer mensaje, después se quita del medio removiendo todo impacto en la performance.

Otra versión muy interesante es hacer que el proxy cargue el objeto decorado en un thread y que haga el #become: cuando termine el proceso de carga.

Como verán, ¡horas de sana diversión en familia!

1 Comentarios:

At 10/5/07 18:11, Blogger Unknown said...

Diego, luego de leer tu libro "Programando con Smalltalk" continuo desorientado en algunas cuestiones, muy probablemente tengan su raiz en errores conceptuales, en este caso en particular no llego a entender la función del objeto Proxy ni como se usa. Prodrias aclararme un poco la cuestión. Otra cosa que hace "loadProxied", ¿como debo definirlo?.
Desde ya muchas gracias.

 

Publicar un comentario

<< Principal