miércoles, agosto 24, 2005

La magia del Smalltalk: Capítulo 10 - ¡No me encuentro!

Los programadores de Smalltalk solemos decir que el ambiente (de Smalltalk) está «vivo» (gracias Dario). La tarea de desarrollo en un ambiente de Smalltalk es muy diferente a la programación en un IDE tradicional o en el vi/emacs.

Es muy, pero muy, raro encontrar «documentación» fuera del ambiente y la documentación que está dentro del ambiente no está en formato de archivos de ayuda, ni html, ni siquiera en texto.

La mejor documentación de un ambiente Smalltalk es el mismo ambiente funcionando.

El ambiente es el mejor ejemplo posible de uso de las clases y de los objetos ya que los casos de uso de los objetos son casos reales que están funcionando delante de nuestros ojos. La documentación en html, pdfs, archivos hlp, etc es demasiado estática y nadie nos garantiza que el ejemplo de uso de tal o cual función o clase sea correcto.

Quizás lo más importante para comenzar a programar en Smalltalk es aprender a usar el ambiente para buscar información.

Lo primero que tenemos que saber es que, en cualquier lugar donde veamos texto, podemos evaluar allí mismo código Smalltalk y acceder a las herramientas.

Una forma de explorar el ambiente es utilizando las herramientas de senders («remitente» o «quien envía el mensaje») e implementors («implementador» o «quien sabe responder al mensaje»).

Seleccionando un fragmento de texto que tenga el envío de un mensaje, podemos pedirle (vía el menú contextual) a nuestro Smalltalk que nos muestro métodos donde el mensaje en cuestión es enviado («senders») o implementaciones del mensaje («implementors»).

Supongamos que necesitamos saber como se usa el mensaje #findTokens:. Para eso escribimos el nombre del mensaje en cualquier panel de texto (por ejemplo en un Workspace) y pedimos la opción «senders» desde el menú contextual o presionando ALT-n.


Seguimos un procedimiento similar para ver las implementaciones del mensaje («implementors»), en este caso presionamos ALT-m.




Y para terminar, una joyita: El MethodFinder.

Esta herramienta puede responder preguntas del tipo: ¿Qué mensajes le puedo enviar a un objeto dado, con unos parámetros dados, para que la respuesta sea la dada?. ¡Qué complicado que quedó escrito!, mejor veamos un ejemplo. Escribimos en el panel de arriba a la izquierda lo siguiente: 'Smalltalk'. $S y aceptamos.


Escribiendo 'Smalltalk'. $S le estamos preguntando al MethodFinder que mensajes le podemos enviar al objeto 'Smalltalk' para que la respuesta sea el objeto $S.

Otro ejemplo sería escribir 'Smalltalk'. 1. $S, en este caso le estamos preguntando que mensaje le podemos enviar al objeto 'Smalltalk', con el parámetro 1, para que la respuesta sea el objeto $S.



Espero que con esto estén un poco menos perdidos.

¡Hasta la próxima!

martes, agosto 16, 2005

La magia del Smalltalk: Capítulo 9 - Colecciones

Pocas cosas tienen un impacto tan grande en la productividad en el desarrollo de software como el manejo de colecciones. Cualquier lenguaje/ambiente de programación que se precie de serio incluye algún framework para el manejo de colecciones.

La combinación de los bloques como objeto de pleno derecho por un lado, el late binding extremo que predica el Smalltalk y el hecho de tener más de 30 años de maduración hacen de las colecciones de Smalltalk uno de los frameworks más poderosos en esta área.

Para empezar veamos el mensaje básico para las colecciones: do:. El mensaje do: le pide a una determinada colección que evalúe un bloque dado por cada elemento que contiene.

'Un string es, obviamente, una colección'
    do: [:each | Transcript show: each; cr]


#(1 2 3 4 5 6 7 8 9 10)
    do: [:each | Transcript show: each; cr]



Veamos algunos mensajes más:

#do:separatedBy:
Evalúa un bloque dado por cada elemento, y evalúa el otro bloque dado entre elementos.
#(1 2 3 4 5 6 7 8 9 10)
    do: [:each | Transcript show: each]
    separatedBy: [Transcript show: ',']


#select:
Devuelve una colección, del mismo tipo que la colección receptora del mensaje, con los elementos para los que el bloque dado devuelve true.
#(1 2 3 4 5 6 7 8 9 10) select: [:each | each odd]
respuesta: #(1 3 5 7 9)


#reject:
Similar a #select:, pero devuelve una colección con los elementos donde el bloque devuelve false.
#(1 2 3 4 5 6 7 8 9 10) reject: [:each | each odd]
respuesta: #(2 4 6 8 10)


#collect:
Devuelve una colección, del mismo tipo que la colección receptora del mensaje, con elementos que son el resultado de la evaluación del bloque por cada elemento del receptor.
#(1 2 3 4 5 6 7 8 9 10) collect: [:each | each * 2]
respuesta: #(2 4 6 8 10 12 14 16 18 20)



¡A coleccionar!

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!

Varios (¿muchos?) libros gratuitos sobre Smalltalk

Stéphane Ducasse se ha tomado el (mucho) tiempo para pedir a la editoriales y a los autores de libros de Smalltalk que ya no se impriman que permitan la publicación on-line.

Ya consiguió los permisos para publicar nada menos que 19 libros.

Pueden bajarlos desde: http://www.iam.unibe.ch/~ducasse/FreeBooks.html

A lo mejor a alguien se le ocurre la excelente idea de traducir alguno al Castellano. ;-)

La magia del Smalltalk: Capítulo 7 - ¿Quién soy?

Un objeto es idéntico sólo a si mismo.

Todos los entornos/lenguajes de OOP nos permiten diferenciar si un par de variables/referencias apuntan al mismo objeto.

Cualquier persona que programe en algún lenguaje de OOP experimentó con este concepto, sin embargo hay 2 cosas interesantes en cuanto a la identidad en Smalltalk.

La primera es que la identidad, en Smalltalk, es más "perdurable". Los objetos NO mueren entre sesiones asÌ que la identidad se mantiene mientras los objetos vivan, y eso es mucho más tiempo que lo que viven los objetos en lenguajes como C++/Java/etc (ver Capítulo 2).

La otra es que Smalltalk permite violar (con perdón de la palabra) la identidad con el mensaje #become:, veamos lo que dice el comentario del método:

"Swap the object pointers of the receiver and the argument. All variables in the entire system that used to point to the receiver now point to the argument, and vice-versa.

Pues si, lo que leen: La operación #become: intercambia todas las referencias a un objeto por referencias a otro objeto, y viceversa.

Es una operación muy poderosa, y a la vez peligrosa. Si quieren hacer trizas a su Smalltalk prueben algunas de las siguientes sentencias y traten de averiguar que fue lo que pasó:

nil become: 'Un string'.

Object become: String.

o mi favorita:

| s1 s2 |

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

s1 become: 'Otro String'.

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


¿Qué raro, no? Bueno, no es tan raro... pero tendrán que esperar hasta otro post para saber porque actúa así.

También tendrán que esperar a otro post para ver ejemplos útiles del uso de #become:.

¡Cuantos misterios! =o)

La magia del Smalltalk: Capítulo 6 - Polimorfismo

La dificultad para definir que son los objetos está dada, justamente, porque no tenemos un concepto más abstracto que el de "Objeto" para refinar. Los objetos son el concepto más abstracto posible.

Como decía en la nota anterior, es imposible definir objeto sin sujeto ni observado sin observador. Eso nos lleva al siguiente concepto de la OOP:


Polimorfismo

Se dice que un objeto es polimórfico con otro cuando un determinado observador no puede distinguirlos entre si. Como en Smalltalk no se puede observar un objeto más que enviándole mensajes, un objeto es polimórfico con otro cuando un determinado observador les envía un conjunto de mensajes y ambos responden de manera indistinguible.


[TAMBIÉN CONTINUARÁ...]

martes, agosto 02, 2005

La magia del Smalltalk: Capítulo 5 - ¿Qué son los Objetos?

Es imposible, siendo argentino como soy, no caer en algún momento en la filosofía barata o en el psicoanálisis. A propósito, ¿Alguien save porqué hay tantos dentistas argentinos en España?.

Dicho lo dicho voy a intentar definir un poco los conceptos fundamentales de la OOP.

Hasta ahora me venía desentendiendo de casi cualquier situación comprometida contestando a cualquier pregunta del tipo:

¿Qué es xxx?
(Reemplace xxx por lo que quiera saber)

Con la clásica respuesta OOP:

xxx es un objeto.

El problema comienza en cuanto el interlocutor se cansa y nos pregunta:

¿Qué son los objetos?

Aclaremos que no valen las clásicas respuestas informáticas que dicen todas más o menos así:

"Un Objeto es una estructura de datos más los procedimientos para impactar sobre esos datos"

Esas respuestas nos dicen como se implementa, en una computadora, la idea de un objeto pero no nos dicen que son realmente los objetos. Se confunde, en esas definiciones, la idea con la implementación de las mismas.

Primero reflexionemos sobre como contestamos a preguntas del tipo:

¿Qué es un perro? ¿Qué es el amor? ¿Qué es el arroz?

Para contestar a esas preguntas, nos valemos de un concepto más abstracto y lo especializamos (lo refinamos) de alguna forma:

Un perro es un animal que ladra y puede morderte.
El amor es un sentimiento que no puede conocerse hasta que se siente.
El arroz
es un cereal con el cual, mi mamá, hace un arroz con leche increíble.


Veamos las definiciones en la Wikipedia:


Perro
El perro es un mamífero que pertenece a la familia Canidae, al igual que los lobos, zorros y coyotes.

Generalmente, el término 'perros' es utilizado para referirse a la raza doméstica (Canis familiaris), la cual se cree que desciende de un ancestro similar al lobo. Algunos científicos sostienen, sin embargo, que el perro es una subespecie de lobo, Canis lupus familiaris.

Arroz
El arroz (Oryza sativa) es una planta de la familia Poaceae, comestible que constituye la base de la dieta en Asia.
Su nutriente principal son los hidratos de carbono, algo de proteínas (7%) y en estado natural bastantes vitaminas y minerales que se suelen perder en gran proporción (hasta un -85% de vitaminas) con los procesos de refinado y pulido.

Amor
El amor es un afecto, sentimiento o emoción que hace desear el bien y la compañía de otro.



Siempre que definimos algo nos basamos en un concepto más abstracto y lo refinamos.

Ahora supongamos que tenemos que definir ese "algo", eso que tienen en común los perros, el arroz y el amor.

La verdad es que no tienen muchas cosas en común los perros, el arroz o el amor (o, al menos yo, no las veo) excepto que sabemos distinguirlos entre si.

No podemos definir Objeto si no hablamos de un Sujeto. No podemos hablar de un Observado si no hay un Observador. No se puede definir un termino sin el otro.

Entonces, siempre que hablamos de un Objeto estamos diciendo también que ese objeto existe porque hay alguien que lo observa, alguien que reflexiona sobre su existencia.

Al reconocer un objeto automáticamente estamos dibujando un límite, una frontera, entre ese objeto y el resto del universo. La tarea de encontrar objetos no es más que la de dibujar fronteras que den un poco de orden al todo.


[CONTINUARÁ...]

Squeak - Un Mundo para Aprender


Ya salió a la calle el nuevo libro de Squeak hecho por un grupo de profesores extremeños y yo (yo sólo escribí el capítulo 1).


Pueden comprar el libro en:



También pueden bajar PDFs con los borradores de los capítulos desde:



¡Qué lo disfruten!

lunes, agosto 01, 2005

Reinventando la rueda


En en sitio http://www.folklore.org/, hay una nota interesante (en inglés) sobre los aportes que Smalltalk le hizo a la Apple Lisa primero, y a la Apple Macintosh después.

La pueden leer en: On Xerox, Apple and Progress