viernes, julio 22, 2005

La magia del Smalltalk: Capítulo 1 - ¡No entiendo nada!

Creo que ya habrá quedado claro (del Capítulo 0) que en Smalltalk todo es un objeto, y que toda la computación se realiza enviando mensajes a los objetos.

Pero, ¿qué sucede cuando le enviamos un mensaje a un objeto?.

Lo que ocurre es que la máquina virtual busca algún método que pueda activar para resolver el mensaje. La búsqueda empieza por la clase del objeto receptor (o la instancia misma, dependiendo del sabor de Smalltalk) y, de no encontrar un método, continua buscando hasta la clase "root" que suele ser Object (o ProtoObject en Smalltalk más modernos).

Hasta ahora no es muy diferente a lo que ocurre en los lenguajes "tradicionales" orientados a objetos (como Java, C++, C#, etc).

¿Qué ocurre cuando no hay un método que sirva para resolver el envío del mensaje? Ocurre que la máquina virtual activa el método #doesNotUnderstand: que, al estar implementado en Object (o en ProtoObject), está siempre disponible para ser evaluado con un objeto de clase Message como parámetro.

En el objeto de clase Message podemos saber el nombre y los parámetros del mensaje original.

El comentario en Object>>doesNotUnderstand: dice:

"Handle the fact that there was an attempt to send the given message to the receiver but the receiver does not understand this message (typically sent from the machine when a message is sent to the receiver and no method is defined for that selector)"

Veamos un ejemplo. Imaginemos un objeto de clase ClaseMágica que tiene implementado el método #doesNotUnderstand: de la siguiente forma:
ClaseMágica>>doesNotUnderstand: aMessage
"The answer is 42"
^ 42

Eso hará que cualquier mensaje enviado a las instancias de ClaseMágica (y subclases) respondan siempre 42 como resultado.

El ejemplo anterior es muy simple y no es demasiado útil (al menos que creamos que la respuesta para todo es 42), pero miremos un ejemplo un poquito más útil:
  • Creamos una clase de nombre Proxy que tenga una variable de instancia llamada target.
  • Creamos un constructor y un método de inicialización para definir cual es el target de nuestro Proxy.
  • Ahora implementamos #doesNotUnderstand: de esta forma:
 Proxy>>doesNotUnderstand: aMessage 
"delegate the message to the receiver's target"
Transcript show: target asString , ' is going to receive the message ' , aMessage asString; cr.
    ^ target
perform: aMessage selector
withArguments: aMessage arguments
  
Lo interesante de este ejemplo es que instancias de clase Proxy pueden hacer de proxy (valga la redundancia) a objetos de cualquier clase. En lenguajes de "early binding" (como el Java, C++, C#, etc) habría que crear una clase de Proxy para cada clase de objeto que queramos envolver y mantenerlas sincronizadas.

Otro ejemplo de uso de DNU (#doesNotUndestand:) lo pueden encontrar en mi paquete de ODBC para Squeak, específicamente en la clase ODBCRow. Este truco permite que las filas de una consulta SQL respondan a mensajes con el nombre de las columnas que genera la consulta, es decir: Si se ejecuta una consulta SQL tipo SELECT firstName, lastName FROM Customer, las filas sabrán responder a los mensajes #firstName y #lastName.

También usé este truco en el paquete rST (Remote Smalltalk) para los proxies que delegan los mensajes desde un Smalltalk a otro.

Si se quedaron con ganas de ver más, miren las clases ObjectTracer y ObjectViewer en sus respectivos Squeak.

2 Comentarios:

At 26/7/05 11:38, Anonymous Anónimo said...

Hola Diego:

Excelente idea de mostrar así a Smalltalk.

Este último con el ejemplo del proxy me fue muy interesante!.

Espero que sigan los artículos!

Saludos.
Germán.

 
At 16/11/05 19:52, Anonymous Anónimo said...

la verdad hermano es que no me sirvio ni pa mierda esto..sigo sin entender un pito....besos y un saludo especial a la materia paradigmas...alumna de utn rosario

 

Publicar un comentario

<< Principal