libro smalltalk

114
por Diego Gómez Deck Programando con Smalltalk Programando con Smalltalk Avda. Portugal, 85-local 28011 Madrid Tlf.: 91 577 03 55/18 Fax.: 91 577 06 18 R esulta muy complicado explicar qué es Smalltalk en toda su dimensión. Smalltalk es considerado el primer lenguaje de programación orientado a objetos. Sin embargo, es mucho más que un mero lenguaje, Smalltalk es un ambiente completo de desarrollo con varios miles de clases y métodos. El ambiente de Smalltalk está compuesto por un extenso grupo de objetos. En Smalltalk TODO es un objeto y TODO es modificable. Y es esta versatilidad la que le permite mejorar dos aspectos claves en el objetivo del desarrollo del software: el aumento de la productividad y generar software de calidad. Con Smalltalk esto es posible y convierte la programación en un proceso mucho más interactivo que el clásico ciclo edición/compilación/ejecución. Sin embargo, este libro no pretende ser un manual básico y de aprendizaje de Smalltalk, para eso ya existen manuales de calidad en el mercado a los que hacemos referencia en esta misma obra. El objetivo del autor al escribir este manual ha sido el de mostrar la filosofía inherente a Smalltalk, la manera en que ésta impacta en la creación de software y, a su vez, cómo esta forma de trabajar genera software de mayor calidad en menos tiempo que con otras herramientas. Desarrollaremos paso a paso algunas aplicaciones de ejemplo para mostrar cómo se trabaja en un ambiente de objetos e iremos introduciendo conceptos y descripciones conforme lo vayamos necesitando. ¡Bienvenidos al mundo fascinante de Smalltalk! Un ambiente de objetos vivos La ilustración de la portada está basada en la obra The computer language “Smalltalk” que Robert Tinney realizó para la portada de la revista BYTE (agosto, 1981). ISBN 84934371-3-1 9 7 8 8 4 9 3 4 3 7 1 3 8

Upload: nahuel-pierini

Post on 24-Jul-2015

220 views

Category:

Documents


4 download

TRANSCRIPT

Page 1: Libro Smalltalk

por

Die

go G

ómez

Dec

k

ProgramandoconSmalltalkPr

og

ram

and

o con Smalltalk

Avda. Portugal, 85-local28011 MadridTlf.: 91 577 03 55/18Fax.: 91 577 06 18

Resulta muy complicado explicar qué es Smalltalk en toda su dimensión. Smalltalk es considerado el primer lenguaje de

programación orientado a objetos. Sin embargo, es mucho más que un mero lenguaje, Smalltalk es un ambiente completo de desarrollo con varios miles de clases y métodos.

El ambiente de Smalltalk está compuesto por un extenso grupo de objetos. En Smalltalk TODO es un objeto y TODO es modificable. Y es esta versatilidad la que le permite mejorar dos aspectos claves en el objetivo del desarrollo del software: el aumento de la productividad y generar software de calidad. Con Smalltalk esto es posible y convierte la programación en un proceso mucho más interactivo que el clásico ciclo edición/compilación/ejecución.

Sin embargo, este libro no pretende ser un manual básico y de aprendizaje de Smalltalk, para eso ya existen manuales de calidad en el mercado a los que hacemos referencia en esta misma obra. El objetivo del autor al escribir este manual ha sido el de mostrar la filosofía inherente a Smalltalk, la manera en que ésta impacta en la creación de software y, a su vez, cómo esta forma de trabajar genera software de mayor calidad en menos tiempo que con otras herramientas.

Desarrollaremos paso a paso algunas aplicaciones de ejemplo para mostrar cómo se trabaja en un ambiente de objetos e iremos introduciendo conceptos y descripciones conforme lo vayamos necesitando.

¡Bienvenidos al mundo fascinante de Smalltalk!

Un ambiente de objetos vivosLa ilustración de la portada está basada en la obra The computer language “Smalltalk” que Robert Tinney realizó para la portada de la revista BYTE (agosto, 1981).

ISBN 84934371-3-1

9 7 8 8 4 9 3 4 3 7 1 3 8

Page 2: Libro Smalltalk

A todos aquellos que saben que la verdadera revolución

de la información no ocurrirá hasta que seamos

capaces de romper unas cuantas barreras

Page 3: Libro Smalltalk

Disculpen mi falta de originalidad, pero tengo que agradecer especialmente

a mi núcleo familiar por el soporte y comprensión que me han brindado.

Mil gracias a mi compañera de viaje Raquel y a mis hijos Nicolás y Nahuel;

ellos son los que realmente han hecho sacrificios para que este libro llegue a

buen término.

Page 4: Libro Smalltalk

7S

Autor:DIEGO GÓMEZ DECK

Responsable editorial:SORAYA MUÑOZ

Responsable de Marketing y Comunicación:ÁLVARO GARCÍA

Diseño y maquetación:CARLOS MONTES

ISBN: 978-84-934371-3-8Depósito Legal:

Edita:©EDIT LIN EDITORIAL, S.L, 2006Avda. Portugal, 85- local28011 Madrid (España)Tels.:91 577 03 55Fax: 91 577 06 18

[email protected]

LICENCIASe permite la copia y distribución de la totalidad o parte de esta obra sin ánimo de lucro. Toda copia total o parcial deberá citar expresamente el nombre del autor, nombre de la editorial e incluir esta misma licencia, añadiendo, si es copia literal, la mención “copia literal”.

Se autoriza la modificación y traducción de la obra sin ánimo de lucro siempre que se haga constar en la obra resultante de la modificación el nombre de la obra originaria, el autor de la obra originaria y el nombre de la editorial. La obra resultante también será libremente reproducida, distribuida, comunicada al público y transformada en términos similares a los expresados en esta licencia.

Impreso en España (Printed in Spain)

*Este libro ha sido realizado con Software Libre, concretamente con: Squeak, OpenOffice.org, Evolution, Mozilla, GIMP.

PRÓLOGO

Page 5: Libro Smalltalk

8S 9S

prologoIntroducción . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Enfoque . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11Metodología . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Alcance del libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Audiencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Licencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Sitio web . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Capítulo 1. ¿Qué es Smalltalk? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.1 Conceptos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Interfaz . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Encapsulación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Polimorfismo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Variables de Instancia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Herencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Programar es simular . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.2 Historia del Smalltalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Aportes del Smalltalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

1.3 ¿Qué es Squeak? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Capítulo 2. Programando con Smalltalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2. 1 La curva de aprendizaje . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.2 Prepararse para un shock cultural . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Tirar código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Trabajo incremental . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .No hay archivos fuentes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.3 El camino es largo, mejor no ir solo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.4 Sintaxis . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Literales . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Mensajes . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Índice

Page 6: Libro Smalltalk

10S 11S

Precedencia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Cascading messages . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Variables . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Los nombres de clases son, también, variables globales . . . . . . . . . . . . . . . . . . . . . . . .Bloques . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Comentarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Método de Ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

2.5 Herramientas . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.6 Librería de Clases y Frameworks . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2.7 Máquina Virtual . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Capítulo 3. ¡Manos a la Obra! . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.1 Modificando Objetos Vivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . El Mundo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Browser de Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Tipos de Browser de Clases . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Categorías de Clase y Métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Squeak y el Ratón . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Foco de teclado . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Workspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Tipos de Workspace . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Evaluando Código . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Sentencias de Ejemplo para evaluar, imprimir, inspeccionar o explorar . . . . . . . . . .Inspector . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Hot-Keys . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

3.2 Parser de XML basado en una Pila . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Smalltalk con Estilo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .NombreDeClase>>nombreDeMétodo

3.3 Importador de Wikipedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Wikipedia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Métodos de Clase vs. Métodos de Instancia . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Plantilla para nuevos métodos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Archivos de ejemplo . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Pre-Depurador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Depurador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Depurador 100% en Smalltalk . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Convención de nombres . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – Set . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Valor de retorno por defecto . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #add: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Explorador . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – OrderedCollection . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Inicialización de objetos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .MessageTallyTimeProfilerBrowser

3.4 Motor de Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Workflow . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Test Driven Development . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .SUnit . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Refactoring Browser . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Refactoring . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Los métodos de testing comienzan por #test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Consejo: Pensar primero en la interfaz pública . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Estructura de los test . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .SUnit Test Runner . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #collect: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Consejo: Es más barato escribir código limpio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Explaining Temporary Variable . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #, . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Consejo: Probar las situaciones límite . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Mensaje #halt . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Consejo – El depurador nos brinda más información a la hora de implementar . . .Colecciones – mensaje #includes: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Senders . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Los tests son, también, documentación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #anySatisfy: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Composed Method . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Los tests aumentan la confianza . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #select:thenCollect: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #select: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – mensaje #at:ifAbsentPut: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Colecciones – Dictionary . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Transcript . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Patrón de Diseño – Adapter . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Métodos privados . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Browser Jerárquico . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .Usar el fuente de un método para crear otro método parecido . . . . . . . . . . . . . . . . .Mensaje #subclassResponsibility . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Capítulo 4. La yapa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.1 Mensaje #become: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.2 Mensaje #doesNotUnderstand: . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.3 Mensajes #perform:, #perform:with:, #perform:withAll:, etc. . . . . . . . . . . . . . . . . . . . . 4.4 Pseudo-variable thisContext . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.5 SLang, máquina virtual y plugins . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.6 FFI – Foreign Function Interface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.7 Metaprogramación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.8 Multithreading . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.9 SqueakMap . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.10 MVC . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.11 Morphic . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4.12 Algunos proyectos con Squeak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Page 7: Libro Smalltalk

Introducción

Smalltalk es mucho más que un lenguaje de programación. Se trata del resultado de un

proceso de investigación y desarrollo, liderado por Alan Kay, que ya lleva más de 30 años

tratando de inventar el ordenador personal. Smalltalk, además de ser un lenguaje de pro-

gramación muy poderoso y versátil, es una interpretación de cómo deberían utilizarse los

ordenadores, ya que estos deberían ser herramientas para amplifi car el espíritu creativo de

las personas.

Smalltalk no es la culminación de esa visión, es sólo un paso. Pero si tiene un objetivo en sí

mismo, ése es el de servir como instrumento para crear la herramienta que vuelva obsoleto

al mismo Smalltalk.

Lamentablemente, las ideas que subyacen de Smalltalk no son las más extendidas en el

mundo de la informática, y aunque muchas innovaciones del proyecto han perdurado

hasta nuestros días, éstas han llegado despojadas de lo fundamental, adquiriéndose sólo la

parte más superfi cial de las ideas. Este hecho ha provocado que la primera experiencia o

toma de contacto con Smalltalk sea negativa y desconcertante, incluso para una persona ya

acostumbrada al manejo de ordenadores y con conocimientos de programación.

No obstante, el esfuerzo de entrar en un área desconocido tiene su recompensa. Muchos,

entre ellos nuestro autor, son los que sienten que Smalltalk les ha devuelto la fascinación

que les produjo usar un ordenador por primera vez. No es extraño ver cómo gente que

comienza a programar, gracias a Smalltalk cambia su concepción de los fundamentos de

los ordenadores. Prácticamente, todos los programadores de Smalltalk utilizan el entorno

no sólo para trabajar y producir software, sino también como una herramienta de investi-

gación. Resulta muy común, por tanto, encontrar proyectos muy peculiares e innovadores

desarrollados con Smalltalk porque, justamente, este entorno sirve como amplifi cador del

espíritu creativo que todos llevamos dentro.

13S

Capítulo 5. Futuroa. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.1 Traits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.2 Tweak . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.3 64 bits . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5.4 OpenCroquet . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Cómo continuara. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Libros Papers o artículos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Grupos de Usuarios . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Conclusión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . ApéndicesBibliografía . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Herramientas usadas en el libro . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .

Page 8: Libro Smalltalk

14S

ProgramandoconSmalltalk

15S

Enfoque

Este libro pretende mostrar a personas con algunos conocimientos de programación,

cómo el hecho de vivir en un ambiente de objetos impacta sobre el ciclo de desarrollo del

software.

La programación con Smalltalk es muy diferente al clásico ciclo edición/compilación/eje-

cución que predomina sobre la mayoría de las herramientas usadas hoy en día, ya que con

este entorno se da un proceso mucho más interactivo. De esta manera, no se penaliza la

investigación ni se castiga de manera más fuerte las primeras decisiones. Al minimizar el

costo de los cambios, se pueden posponer las decisiones más importantes del diseño hasta

el momento en que tengamos los conocimientos lo sufi cientes. Esto es, en Smalltalk se pro-

mueve un método de desarrollo donde el software se modifi ca conforme se va generando.

Esta obra pretende mostrar una parte de todo ese proceso, para lo que desarrollaremos

algunas aplicaciones de ejemplo paso a paso e iremos introduciendo conceptos,

descripciones, etc. conforme lo vayamos necesitando. Bien, estos casos prácticos nos

servirán de excusa para mostrar el uso del entorno de Smalltalk, no son objetivos en sí

mismos y no se van a desarrollar al 100%.

Metodología

Aunque todos los programadores Smalltalk comparten ciertas costumbres, cada uno lo

confi gura y utiliza de forma diferente, ya que programar en este entorno se convierte

en tarea muy personal, puesto que no olvidemos que ha nacido como la concepción del

ordenador personal.

En este manual el autor nos va a mostrar cómo usa él el entorno, lo que no quiere decir que

sea la única o mejor manera de trabajar en Smalltalk. Del mismo modo, tampoco pretende

imponer su forma de trabajo ni nada parecido, desea que cada uno de nosotros hagamos

uso de Smalltalk de la forma que más nos guste, y que compartamos con la comunidad las

mejoras que consigamos en nuestros entornos.

Probablemente, reconoceremos algunos aspectos de las, ahora denominadas, metodologías

ligeras. Bien, esto no debería extrañarnos, ya que la principal metodología ágil, que es la

Extremme Programming (Programación Extrema), se formalizó en un proyecto desarrollado

con Smalltalk, del que Kent Beck formaba parte.

Alcance del libro

Este libro no es una guía completa de Smalltalk, sólo pretende mostrar la fi losofía de uso

del entorno y servir de referencia para nuevos usuarios de Smalltalk.

La mayoría de las respuestas a las preguntas que nos hacemos cuando programamos en este

entorno, están dentro del mismo Smalltalk. Por esta razón, esta documentación pretende

enseñarnos a buscar esas respuestas en el entorno, en lugar de contestarlas directamente.

En el apéndice dedicado a la bibliografía, el autor ha incluido un listado de referencias de

manuales sobre Smalltalk que pueden servir como complemento a este libro. Algunos de

esos títulos pueden ser descargados gratuitamente de Internet.

Audiencia

El libro que el lector tiene en sus manos no pretende ser una guía para aprender a progra-

mar desde cero, sino que se presupone que el lector tiene conocimientos básicos de progra-

mación, incluso, que está familiarizado con los conceptos de la programación orientada

a objetos.

Por tanto, este manual pretende ser la referencia para programadores que estén buscando

nuevas y mejores formas de producir software y que vean en Smalltalk una opción alter-

nativa y válida. Es más, aunque no se tenga la oportunidad de usar Smalltalk en el día a

día, conocer este entorno y el paradigma de objetos tal cual fue creado, les convertirá en

mejores programadores.

Licencia

Hemos pretendido ser fi eles al ideal de libertad que rigió el desarrollo del proyecto Smalltalk,

por lo que hemos publicado este libro bajo una licencia que permite la libre circulación de

los contenidos de sus contenidos.

Se permite la copia y distribución de la totalidad o parte de esta obra sin ánimo de lucro.

Toda copia total o parcial deberá citar expresamente el nombre del autor, nombre de la edi-

torial e incluir esta misma licencia, añadiendo, si es copia literal, la mención “copia literal”.

Page 9: Libro Smalltalk

16S 17S ¿Qué es Smalltalk / Squeak?

?

Se autoriza la modifi cación y traducción de la obra sin ánimo de lucro siempre que se haga

constar en la obra resultante de la modifi cación el nombre de la obra originaria, el autor de

la obra originaria y el nombre de la editorial. La obra resultante también será libremente

reproducida, distribuida, comunicada al público y transformada en términos similares a los

expresados en esta licencia.

Sitio web

El enfoque de esta obra hace que sea prioritario reducir al mínimo el tiempo de espera

antes de adentrarse en el entorno, ya que la experiencia es fundamental para aprender a

usar Smalltalk.

Para acelerar el proceso inicial, nuestro autor ha trabajado sobre una imagen de Squeak

pre-confi gurada con las herramientas más habituales a la hora de programar. En uno de

los apartados del libro se explica en detalle qué aspectos se instalaron y modifi caron sobre

un Squeak virgen.

Podemos encontrar la imagen, así como otros datos de interés relacionados con este libro,

en el wiki:http://smalltalk.consultar.com

SMALLTALK/SQUEAKCAPÍTULO 1CAPÍTULO 1

Resulta muy complicado ofrecer una explicación exacta acerca de qué es Smalltalk y por

qué es tan diferente a otras herramientas de programación más populares y utilizadas por

los desarrolladores.

El origen del distanciamiento por parte de la comunidad de desarrolladores respecto a este

entorno, es consecuencia de que el proyecto Smalltalk estuvo - y sigue estando - regido por

una concepción diferente acerca de cómo usar los ordenadores. Este concepto que siempre

ha marcado la línea de Smalltalk puede resumirse, en palabras de nuestro autor, en esta

frase:

“Las computadoras deben ser herramientas que sirvan como amplifi cadores

del espíritu creativo de las personas”.

Esto implica, entre otras cosas, las siguientes afi rmaciones:

ß Todo el sistema tiene que ser inteligible y, por consiguiente, modifi cable, por una sola persona.

QUÉ ES¿

Page 10: Libro Smalltalk

18S

ProgramandoconSmalltalk

19S ¿Qué es Smalltalk / Squeak?

ß El sistema tiene que estar construido con un mínimo juego de partes intercambiables.

Cada parte puede ser modifi cada sin que altere el resto del sistema.

ß Todo el sistema tiene que estar construido basándose en una metáfora que pueda ser

aplicada en todas las partes que lo constituyen.

ß Cada componente del sistema ha de poder ser inspeccionado y modifi cado.

“Smalltalk es un ambiente de objetos.

Los objetos interactúan enviándose mensajes entre sí”.

Smalltalk incluye un lenguaje de programación que también ha sido desarrollado usando los

principios que hemos enumerado anteriormente. Esto quiere decir, por ejemplo, que el lenguaje

Smalltalk puede ser modifi cado - como cualquier otra parte - y reemplazado por otro, o que pueden

convivir diferentes lenguajes de programación en el mismo ambiente, entre otros aspectos.

Un entorno de Smalltalk típico también está constituido por muchas herramientas que

asisten en la tarea de programación. Y, como todo en este entorno, son suceptibles de ser

modifi cadas o reemplazadas por otras.

Asimismo, el entorno de Smalltalk incluye objetos para crear interfaces gráfi cas de usuarios.

Eso sí, todo escrito en Smalltalk, todo a la vista y todo modifi cable.

Los lectores tienen ante sí un libro de programación para desarrolladores con un mínimo

de conocimiento, por lo que vamos a centrarnos en las posibilidades que ofrece un entorno

Smalltalk para la creación de software. No obstante, hemos de tener muy presente que las

ideas sobre las que se fundamenta Smalltalk son lo sufi cientemente poderosas como para

generar un sistema operativo completo. Estas ideas tienen la capacidad de convertir el

uso de los ordenadores en una actividad mucho más creativa que la mera experiencia que

tenemos al trabajar con software que usamos normalmente.

Desde el punto de vista de simples programadores, podemos decir que Smalltalk:

ß Incluye un lenguaje de programación

ß Incluye una librería de clases

ß Incluye un entorno de desarrollo.

Tanto el lenguaje, como la librería de clases y el entorno de desarrollo llevan más de 30

años de uso y depuración. No en vano, Smalltalk ha sido la referencia para el desarrollo de

lenguajes y entornos de programación.

1.1 Conceptos

Smalltalk está defi nido por un conjunto muy pequeño de conceptos, pero que poseen un

signifi cado muy específi co. Resulta fácil confundir los conceptos porque estos son usados

en distintos lenguajes, con defi niciones muy diferentes también.

Objetos

Todo en Smalltalk es un objeto.

Un objeto es una parte perfectamente diferenciada del resto del ambiente, con características

y responsabilidades bien defi nidas.

Mensajes

Un mensaje es un requerimiento que se le hace a un objeto determinado para que éste lleve

a cabo algunas de sus responsabilidades.

Por tanto, un mensaje especifica qué es lo que se espera del receptor (el objeto que

recibe el mensaje) pero no obliga a responder de una determinada manera. Esto es, el

receptor es el responsable de decidir cómo se lleva a cabo la operación para contestar

al mensaje.

Interfaz

El juego de mensajes que un determinado objeto puede entender se denomina su interfaz.

Por tanto, la única forma de interactuar con un objeto es a través de su interfaz.

Encapsulación

Se llama encapsulación al hecho de que ningún objeto puede acceder a la estructura interna

de otro objeto. Así pues, sólo el objeto conoce, y puede manipular, su propia estructura

interna.

Mensajes

Interfaz

Encapsulación

Page 11: Libro Smalltalk

S20S

ProgramandoconSmalltalk

21S ¿Qué es Smalltalk / Squeak?

Esto, sumado a que los mensajes sólo especifi can qué se espera del receptor pero no indican

cómo se debe realizar la tarea, asegura que ningún objeto dependa de la estructura interna

de otro.

El envío de mensajes junto a la encapsulación permiten el desarrollo de sistemas muy

modulares, ya que cualquier parte del mismo puede ser reemplazada por otra mientras

ésta última respete la interfaz de la parte reemplazada.

Polimorfi smo

Dos objetos son polimórfi cos entre sí cuando un determinado emisor no puede distinguir

uno del otro. Dicho de otra forma, si podemos cambiar un objeto por otro, en un

determinado contexto, es porque son polimórfi cos.

Clases

Una clase describe la implementación de un conjunto de objetos.

Los objetos individuales descritos por las clases se llaman instancias. La clase describe la

estructura interna de los objetos, al igual que especifi ca, también, cómo se responde a los

mensajes.

Variables de instancia

La estructura interna de los objetos está compuesta por variables de instancia. Así pues, las

variables de instancia son nombres que el objeto puede usar para hacer referencia a otros

objetos.

Métodos

Los métodos son la manera de especifi car cómo responden a los mensajes los objetos de

una determinada clase. Cada método especifi ca cómo se lleva a cabo la operación para

responder a un determinado mensaje.

Un método puede acceder a la estructura interna del objeto así como, también, enviarse

mensajes a sí mismo o a otros objetos. Los métodos describen, igualmente, cuál es la

respuesta que recibe el emisor (el objeto que envía el mensaje).

Todos los objetos de Smalltalk son instancia de alguna clase. La programación en Smalltalk,

por tanto, consiste en crear clases, crear instancias de esas clases y especifi car la secuencia

de envío de mensajes entre esos objetos.

Herencia

Las clases, en Smalltalk, están organizadas jerárquicamente. Una clase refi na el concepto de

otra clase más abstracta. La clase más abstracta es Object. Todas las clases son herencias de

Object (porque todo es un objeto) o herencia de alguna clase que hereda de Object.

La relación que existe entre la clase más abstracta (la superclase) y la clase más concreta (la

subclase) permite clasifi car el conocimiento que tengamos del dominio diseñado.

1.2 Programar es simular

Programar con objetos es programar una simulación. La metáfora en la programación

con objetos está basada en personifi car a un objeto físico o conceptual del dominio real en

objetos simulados del ambiente. O lo que es lo mismo, tratamos de dar vida a los objetos

reales en el ambiente dotándolos de las mismas características y funcionalidades que los

objetos reales a los que representan.

1.3 Historia del Smalltalk

Smalltalk (no se escribe SmallTalk, ni Small-talk, ni Small-Talk) es un proyecto que lleva

más de 30 años de desarrollo. Éste fue inventado por un grupo de investigadores liderados

Polimorfi smo

Clases

Variables de instancia

Métodos

Herencia

Smalltalk en el año 1977

por Alan Kay, en Xerox PARC

(Palo Alto Research Center), du-

rante la década de los 70. Dicho

proyecto de investigación dio lu-

gar a varios resultados interme-

dios que fueron conocidos como

Smalltalk/71, Smalltalk/72, Sma-

lltalk/76 y Smalltalk/80 (http://

en.wikipedia.org/wiki/Smalltalk)

Page 12: Libro Smalltalk

22S

ProgramandoconSmalltalk

23S ¿Qué es Smalltalk / Squeak?

La versión del Smalltalk usadaactualmente es un descendiente directo del Smalltalk/80 y

conserva prácticamente todas sus características. El proyecto, desde sus inicios, ha generado

una gran cantidad de invenciones que han llegado hasta nuestros días.

Aportes del Smalltalk

Por razones que desconoce nuestro autor, el proyecto Smalltalk no cuenta con la reputación

y la fama que se merece. En la actualidad, es muy frecuente encontrarse con profesionales

de la informática que no conocen nada acerca del proyecto ni de sus aportes. Sin embargo,

utilizamos a diario algunas de las ideas que se han desarrollado en Smalltalk y muy pocos

desarrolladores son conscientes de ello.

Ordenador personal

La idea de que cada persona pueda disponer de un ordenador de uso personal, con una

potencia de cálculo sufi ciente como para ser la herramienta de acceso a la información,

tiene sus raíces en las ideas de la Dynabook de Alan Kay (http://en.wikipedia.org/wiki/

Dynabook).Dynabook).

S Maqueta de la Dynabook.

Interfaces gráfi cas de usuario

Smalltalk, desde sus inicios, ha contado con una intuitiva interfaz gráfi ca de usuario ma-

nejable por un ratón. Las ventanas superpuestas, las barras de desplazamiento, la función

de copiar y pegar, los menús de contexto, etc... forman parte de todos los desarrollos del

proyecto que, años más tarde, Apple ayudó a masifi car.

Informática

Resulta difícil enumerar la cantidad de aportes que Smalltalk ha hecho a la informática en

general. Empezando, por ejemplo, con el paradigma de orientación a objetos y terminando

con aspectos más técnicos como la operación BitBlt (http://en.wikipedia.org/wiki/Bit_blit).

Pero la lista continúa con las metodologías ágiles (http://en.wikipedia.org/wiki/Extreme_

Programming), los patrones de diseño (http://en.wikipedia.org/wiki/Design_Patterns), el

concepto de entorno de desarrollo... o conceptos como Unit Testing (http://en.wikipedia.

org/wiki/Unit_test), Refactoring y Refactoring Browser (http://en.wikipedia.org/wiki/Refac-

toring).

Asimismo, el proyecto Smalltalk también ha ayudado a afi anzar el uso de los lenguajes

dinámicos, los recolectores de basura, el uso de máquinas virtuales y un largo etcétera.

1.4 ¿Qué es Squeak?

Squeak es un Smalltalk moderno, de código abierto, escrito en sí mismo, muy portable y

muy rápido. En la actualidad, Squeak puede correr en plataformas Windows, Apple, Linux,

iPaqs, etc.

Puede considerarse a Squeak como la continuación del proyecto original de Smalltalk y

cuenta con los aportes de varios de los desarrolladores originales de los años 70, como Alan

Kay, Dan Ingalls, Ted Kaehler...

S Smalltalk en el año 80

Aportes del Smalltalk

Ordenador personal

Interfaces gráfi cas de usuario

Page 13: Libro Smalltalk

24S

ProgramandoconSmalltalk

25S ¿Qué es Smalltalk / Squeak?

S

Maqueta de la Dynabook.

La comunidad de desarrolladores y usuarios de Squeak se extiende por todo el mundo,

cubriendo un gran abanico de áreas, entre ellos: educación, investigación, desarrollo mul-

timedia, desarrollo web, entre otros.

Squeak versión 3.4.

El proyecto Squeak comenzó en Apple, en el año 1995, porque los autores necesitaban un

entorno de desarrollo de software educativo que pudiera ser usado – e incluso programado –

por personas no técnicas. Los detalles de la motivación que dio lugar al proyecto Squeak

pueden leerse en el documento “Back to the Future – The Story of Squeak, a practical Small-

talk written in itself ” (ver bibliografía).

Squeak, en cierta forma, es un regreso a las ideas que habían motivado todo el desarrollo

del proyecto Smalltalk en los 70. Algunos de los dialectos comerciales de Smalltalk han

perdido parte de la concepción original y Squeak vuelve a retomar esos valores. Todo lo

que pueda hacerse con un ordenador, tiene que poder hacerse con Squeak.

La aplicación de dicho concepto convierte a Squeak en un ambiente muy multimedia,

donde todos los medios de expresión y soporte de información pueden confl uir en una

única herramienta. Squeak cuenta con excelente soporte para gráfi cos 2D y 3D, procesa-

miento de texto y numérico, música (MP3, MIDI, generador de sonido FM), procesamien-

to de vídeo, entre otras muchas funcionalidades.

Además, Squeak también dispone de excelentes herramientas de programación como el Re-

factoring Browser, editores de código con sintax-highlight, framework para unit-testing, etc.

Y, por supuesto, incluye inmejorables opciones para desarrollo de software comercial como

Seaside (un frameworks de desarrollo de aplicaciones web basado en continuations), acceso

a bases de datos ODBC, bases de objetos como Magma, rST – Remote Smalltalk (soporte

de objetos distribuidos), etc.

A día de hoy, fi nales de enero de 2006, existen más de 600 paquetes con aplicaciones para

instalar en Squeak registradas en SqueakMap (http://map1.squeakfoundation.org/sm).

Squeak es el dialecto de Smalltalk escogido para este libro. Sin embargo, hay que saber que

el 95% de lo que se aprenda en un determinado dialecto es perfectamente válido para el

resto de los dialectos. Por tanto, si Squeak no es la herramienta que más nos guste, pode-

mos probar con cualquiera de las otras alternativas que nos ofrece Smalltalk.

Page 14: Libro Smalltalk

27S Programando con Smalltalk

El comienzo con Smalltalk, en un principio, puede resultar complicado para personas

que proceden de otros entornos. Por ello, vamos a hacer mención a algunos consejos y

comentarios con el objetivo de facilitar su acceso.

2.1 La curva de aprendizaje

¿Preparados para un nivel de aprendizaje alto en nuestro primer contacto con Smalltalk?

Como hemos comentado en la Introducción, Smalltalk ofrece una perspectiva distinta

acerca de cómo debería ser nuestra experiencia con los ordenadores. Esa novedosa

concepción es la causa del desconcierto que puede provocar el primer acercamiento con

Smalltalk entre los usuarios ya iniciados en informática.

2.2 Shock cultural

La mayoría de las desavenencias iniciales tienen que ver con esta forma distinta de ver y

entender la informática.

Smalltalk no es difícil, sólo es diferente.

CONSMALLTALK

CAPÍTULO 2CAPÍTULO 2 PROGRAMANDO

2.1

2.2

Page 15: Libro Smalltalk

28S

ProgramandoconSmalltalk

29S Programando con Smalltalk

2.3 Tirar código

El código escrito es importante, pero lo es mucho más el conocimiento que vamos

obteniendo a conforme programamos.

Si adquirimos conocimiento en el día a día, probablemente el código antiguo ya no nos sea

de tanta utilidad. Tirar código no es malo, sin embargo, el no aprender a diario sí que nos

puede resultar negativo como programadores.

2.4 Trabajo incremental

Un ambiente como Smalltalk es ideal para trabajar de forma incremental. Los vicios que

hemos adquirido, como consecuencia del ciclo de desarrollo edición/compilación/prueba,

no tienen sentido en Smalltalk y, en cierta manera, tenemos que aprender a programar de

forma distinta.

Por otro lado, los cambios en Smalltalk suponen mucho menos esfuerzo que en otros

lenguajes, aspecto que permite relajarse y demorar las decisiones importantes de diseño

hasta que sepamos sufi ciente acerca del dominio. No es de extrañar, por tanto, que las

metodologías ágiles hayan sido desarrolladas en Smalltalk.

2.5 No hay archivos fuentes

En Smalltalk no existe un archivo con los fuentes, es más, el código está dentro del ambiente

de objetos. No obstante, esto no impide mover código entre imágenes de Smalltalk, incluso,

existen distintas opciones para trasladar código de un ambiente Smalltalk a otro.

2.6 El camino es largo, mejor no ir solo

Quizás la forma más fácil de aprender Smalltalk sea al lado de un experto, aunque sabemos

que es difícil conseguir un tutor a tiempo completo y de forma presencial. Sin embrago, al

igual que en otras comunidades de programadores, para Smalltalk también existen listas

de correos y grupos de usuarios que pueden ayudarnos bastante en los comienzos.

2.7 Sintaxis del lenguaje

Prácticamente todo el paradigma de objetos se puede resumir en objetos que reciben men-

sajes. La sintaxis Smalltalk es una consecuencia directa de ello, así, su estructura básica es:

2.4

2.7.1 Expresiones

Smalltalk es un lenguaje que está basado en expresiones. Por tanto, una expresión es una

secuencia de caracteres que puede ser evaluada.

La expresiones pueden ser de cuatro tipos: literales, variables, expresiones de mensajes y

expresiones de bloque.

Literales

Algunos objetos son conocidos por el compilador y pueden ser instanciados (crear

un objeto a partir de una clase específi ca en la programación orientada a objetos) con

literales.

El valor de una expresión literal es siempre el mismo objeto. A continuación vamos a ver

los distintos tipos de constantes literales.

Números

Smalltalk cuenta con una rica variedad de objetos numéricos: enteros (SmallInteger,

LargePositiveInteger y LargeNegativeInteger), coma fl otante (Float), fracciones (Fraction),

decimales (ScaledDecimal), etc.

Estos están representados por una secuencia de dígitos que pueden estar precedidos por un

signo – y/o un punto decimal.

Algunos de esos objetos pueden instanciarse usando los siguientes literales.

2.7

objeto mensaje.

Literales

Números

“Enteros”1.-1.12345678901234567890.-12345678901234567890.

“Coma fl otante”1.1.-1.1.12345678901234567890.0.-12345678901234567890.0.

Page 16: Libro Smalltalk

30S

ProgramandoconSmalltalk

31S Programando con Smalltalk

Caracteres

Los caracteres (Character) pueden instanciarse, también, usando constantes literales.

Siempre deben estar precedidos por el símbolo $.

Caracteres

“Caracteres”$a.$b.$á.$1.$$.

Cadenas de caracteres

Las cadenas (String) son una secuencia de caracteres. Éstas responden a mensajes para

acceder a caracteres individuales, sustituir secuencias, compararlas con otras y concate-

narlas.

La secuencia de caracteres se representa encerrada entre comillas ‘’.

Símbolos

Los símbolos (Symbol) son cadenas de caracteres (String) usadas por el sistema como

nombre de clase, métodos, etc. Nunca aparecerán, en todo el sistema, dos símbolos con los

mismos caracteres, lo que permite comparaciones muy rápidas.

Los símbolos se representan como una secuencia de caracteres alfanuméricos precedidos por #

Cadenas de caracteres

Símbolos

“Cadena de Caracteres”‘!Hola mundo!’.‘Smalltalk’.‘áéíóú’.‘Un string con una comilla simple (‘’)’

Cada elemento que constituye un Array es un literal. Por lo que el literal para crear un

Array es una secuencia de literales separadas por espacios en blanco, encerradas entre pa-

réntesis ( ). y precedidas por #.

En Squeak (y en ningún dialecto más) se puede instanciar un Array con el resultado de la

evaluación de expresiones Smalltalk separadas por un punto y encerradas entre llaves {}.

ß Mensajes Los mensajes representan la interación entre los componentes de un sistema

Smalltalk. Un mensaje es un encargo que un objeto le hace a otro objeto.

Por tanto, el mensaje está compuesto por el receptor (el objeto al que se le da el aviso), el

selector (el nombre del mensaje) y, si corresponde, por los argumentos.

Desde el punto de vista sintáctico, hay tres tipos de mensajes: Unary, Binary y Keyword.

ß Mensajes Unary Los mensajes Unary son mensajes sin argumentos. De ahí que sean los

más simples y sólo consten de:

receptor mensaje.

“Símbolos”#unSímbolo.#’un símbolo con espacios’.

ArrayUn Array (arreglo) es una estructura de datos simple que permite acceder a los elementos

contenidos indicando la posición con un número.

Array

En Squeak (y en ningún dialecto más) se puede instanciar un Array con el resultado de la

“Array”#(1 2 3 4).#(1 1.0 $a ‘un string’ #unSímbolo).#(#(1) #(2)).

“Arrays en Squeak”{1 + 1. 2 class}.{#(1) class}.

“Ejemplos de mensajes Unary”-1 abs.2 class.1000 factorial.‘aeiou’ size.Date today.Time now.OrderedCollection new.#símbolo class.String category.

Page 17: Libro Smalltalk

32S

ProgramandoconSmalltalk

33S Programando con Smalltalk

al receptor. Por otro, el receptor devuelve información con un objeto como resultado

del envío de mensajes.

Los métodos, que son la forma que tienen los objetos de responder a los mensajes,

pueden especifi car el valor de retorno usando el carácter ^.

Precedencia

Los mensajes se evalúan de izquierda a derecha. Así, los mensajes Unary tienen pre-

cedencia sobre los Binary y, a su vez, los Binary tienen precedencia sobre los mensajes

Keyword.

No obstante, siempre se pueden romper las reglas de precedencia utilizando el paréntesis.

Las simples reglas de precedencia, de la sintaxis Smalltalk, tienen algunas implicacio-

nes imprevistas para personas acostumbradas a otros lenguajes de programación. Por

ejemplo, en Smalltalk el compilador no sabe de sumas y multiplicaciones. Esto impli-

ca que el compilador no puede determinar que, cuando operamos con números, la

multiplicación tiene precedencia sobre la suma.

Bien, analicemos la siguiente sentencia:

ß Mensajes Binary La sintaxis de los mensajes binarios tiene un sólo argumento, además

del receptor y selector.

Los mensajes Binary están constituidos de la siguiente forma:

receptor unOperador argumento.

Los operadores válidos están compuestos por uno o más de los siguientes caracteres:

- ~ ! @ % & * + = \ | ? / > < ,

“Ejemplos de mensajes Binary”3 + 5.3 > 7.3 = 5.2 @ 10.‘Un String ‘, ‘concatenado a otro’.‘Alan Kay’ -> Smalltalk.

ß Mensajes Keyword Los mensajes Keyword están formados por una o más palabras

claves, con sus respectivos argumentos, con la siguiente estructura:

receptor palabraClave1: argumento1.

O, también, de esta manera:

receptor palabraClave1: argumento1 palabraClave2: argumento2.

Y así con tres, cuatro o más palabras claves y sus respectivos argumentos, pero la palabra

clave siempre termina en :

Valor de retorno

El lenguaje Smalltalk provee un mecanismo doble de comunicación. Por un lado, el

selector y los argumentos del mensaje permiten que el emisor le envíe información

Valor de retorno

“Ejemplos de mensajes Keyword”‘Un String’ fi rst: 3.‘Un String’ allButFirst: 3.‘Un String’ copyFrom: 2 to: 5.5 between: 1 and: 10.1 to: 5.Array with: 1 with: nil with: ‘string’

unMétodoConValorDeRetorno2 “Este es un ejemplo de método que responde al mismo receptor como valor de retorno.

Si el método no tiene un valor de retorno explícito, el receptor es el resultado”

unMétodoConValorDeRetorno1 “Este es un ejemplo de método que responde nil como valor de retorno”

^ nil

Las simples reglas de precedencia, de la sintaxis Smalltalk, tienen algunas implicacio-

‘string’ at: -2 negated >>> ‘string’ at: (-2 negated)

‘string’ at: 2 + -1 negated >>> ‘string’ at: (2 + (-1 negated))

3 + 2 * 4 >>> 20

Page 18: Libro Smalltalk

Los nombres de clases son, también, variables globales

Cuando se crea una clase, Smalltalk genera una variable global que hace referencia

al objeto clase. De ahí se desprende que la convención de nombres de clase sea la

misma que la convención de nombres de variables globales.

34S

ProgramandoconSmalltalk

35S Programando con Smalltalk

Según las reglas de precedencia de Smalltalk, se envía primero el mensaje + (con el

argumento 2) y al resultado (5) se le envía el mensaje * (con el argumento 4). De esa

forma, el resultado es 20 y no 11 como hubiese sido lo normal en otros lenguajes.

No obstante, hemos de saber que siempre podemos utilizar paréntesis para forzar la

precedencia que deseamos:

La estructura de un nombre de variable se compone de una secuencia de letras y dígitos,

pero siempre empezando por una letra. Las variables temporales y de instancia comienzan

con una letra minúscula y las globales comienzan con una mayúscula.

Otra convención en lo que respecta al nombre de las variables es que, si éste está compuesto de

varias palabras, cada una (excepto la inicial en algunos casos) debe comenzar por mayúscula.

Una constante literal siempre se refi ere a un único objeto, pero una variable puede referirse

a distintos objetos en diferentes momentos.

Tipos de variables

Existen dos tipos de variables: variables privadas y variables compartidas.

Variables privadas

Estas variables sólo son accesibles por un objeto y, a su vez, pueden ser: variables de

instancia y variables temporales.

3 + (2 * 4) >>> 11

Cascading messages (mensajes en cascada)

En algunas ocasiones es necesario enviarle varios mensajes al mismo receptor. En el

lenguaje Smalltalk existe una forma sintáctica de enviar más de un mensaje al mismo

receptor.

Esta manera de la que hablamos consiste en terminar el envío del primer mensaje con

el carácter punto y coma ; y, a continuación, escribir el siguiente mensaje.

ß Variables La memoria disponible para un objeto se organiza en variables. Todas las va-

riables tienen un nombre y cada una de ellas hace referencia a un único objeto en cada

momento.

Todas las variables han de declararse antes de usarlas, la declaración consiste en una sen-

tencia en la que fi gura el tipo de dato y el nombre que asignamos a la variable. Una vez

declarada se le podrá asignar valores.

El nombre de las variables puede ser usado en expresiones que quieran hacer referencia a

ese objeto.

La memoria disponible para un objeto se organiza en variables. Todas las va-

“Mensajes en cascada”Transcript clear; show: ‘algo en el Transcript’; cr; show: ‘y algo más’; cr.

métodoDeEjemplo: argumento “Este método muestra el uso de diferentes tipos de variables.

La estructura de un nombre de variable se compone de una secuencia de letras y d

argumento: argumento al método variableTemporal: variable temporal al método variableDeInstancia: variable de instancia Smalltalk: variable global each: argumento para el bloque ” | variableTemporal |

variableTemporal := Smalltalk allClasses.

variableDeInstancia := variableTemporal select:[:each | | variableTemporalAlBloque | variableTemporalAlBloque := 1. each name beginsWith: argumento

].

Page 19: Libro Smalltalk

36S

ProgramandoconSmalltalk

37S Programando con Smalltalk

Las variables de instancia representan el estado del objeto y perduran durante toda

la vida de éste. Dos objetos diferentes, aunque pertenezcan a la misma clase, pueden

tener valores diferentes en sus variables de instancia.

Además, las variables de instancia pueden ser nombradas (cuando tienen asociado un

nombre y se las identifi ca a través de él) e indexadas (no tienen nombre, por lo que

sólo se puede acceder a ellas enviando un mensaje a la instancia con un índice espe-

cifi cando a qué variable quiere accederse).

Las variables temporales están defi nidas al comienzo de un método. A diferencia de

las variables de instancia, éstas sólo perduran mientras permanece en activo el méto-

do, bloque o programa, representando, así, un estado transitorio del objeto.

variable := ExpresiónSmalltalk.

Pseudo-variables

Una pseudo-variable es un identifi cador que referencia a un objeto. La diferencia con

las variables normales es que no se pueden asignar y siempre aluden al mismo objeto.

Esto es, el valor de una pseudo-variable no puede modifi carse con una expresión de

asignación.Variables compartidas

Las variables compartidas son..........................................................................................

..............................................................y también pueden ser de tres tipos: variables de

clase, variables pool y variables globales.

Las variables de clase son compartidas por las instancias de una clase y sus subclases,

manteniendo el mismo valor para todas las instancias. Estas variables se declaran en

la defi nición de la clase.

Las variables pool son variables compartidas por un subconjunto de clases en el sis-

tema y almacenadas en diccionarios Pool (que son colecciones de variables cuyo

ámbito es un subconjunto defi nido de clases en el sistema). Es necesario declarar en

la defi nición de la clase el nombre del diccionario Pool que las contiene, para poder

acceder a ellas.

Y, por último, las variables globales son aquellas variables compartidas por todos los

objetos.

Asignación

El objeto referenciado por una variable cambia cuando una asignación es evaluada.

Las asignaciones, en Smalltalk, tienen la siguiente estructura:

“Ejemplos de asignaciones”x := 0.y := 1.punto := x @ y.clases := Smalltalk allClasses.

“Pseudo-variables constantes”

nil. “Referencia a un objeto usado cuando hay que representar el concepto de ‘nada’ o de ‘vacío’. Las variables que no se asignaron nunca, referencian a nil”

true. “Referencia a un objeto que representa el verdadero lógico.”

false. “Referencia a un objeto que representa el falso lógico.”

“Pseudo-variables no-constantes”self. “Referencia al receptor del mensaje.”

super. “Referencia al receptor del mensaje, pero indica que no debe usarse la clase del receptor en la búsqueda del método a evaluar. Se usa, sobre todo, cuando se especializa un método en una subclase y se quiere invocar el método de la superclase.”

thisContext. “Referencia al objeto contexto-de-ejecución que tiene toda la

información referente a la activación del método.”

ß Bloques En Smalltalk el comportamiento (el código) también es un objeto. Los bloques

son una forma de capturar comportamiento (código) en un objeto para utilizarlo a nuestra

discreción.

Page 20: Libro Smalltalk

38S

ProgramandoconSmalltalk

39S Programando con Smalltalk

La forma básica de un bloque es una lista de expresiones, separadas por un punto,

encerradas entre corchetes [].

[ExpresiónSmalltalk1].

[ExpresiónSmalltalk1. ExpresiónSmalltalk2].

La forma de activar un bloque (de ejecutar el código que encierra) es enviándole el mensaje

#value. La última expresión del bloque será el valor de retorno.

“Ejemplo con un bloque sin argumentos ni variables temporales”

| bloque |bloque := [World fl ash]. “En este punto el mundo NO parpadea”bloque value. “Ahora que evaluamos el bloque el mundo SI parpadea”

Un aspecto a muy interesante del lenguaje Smalltalk es que no existen, como parte de

la sintaxis, las estructuras de control (Las formas de iteración sirven para ejecutar ciclos

repetidamente, dependiendo de que se cumplan ciertas condiciones. Una estructura de

control que permite la repetición de una serie determinada de sentencias se denomina

bucle1 (lazo o ciclo).

La funcionalidad que, en los lenguajes tradicionales, se da con extensiones en la sintaxis, en

Smalltalk se resuelve con mensajes a objetos.

“Estructuras tipo IF”Smalltalk allClasses size > 2000 ifTrue:[Transcript show: ‘¡Cuantas clases!’; cr].

Smalltalk allClasses size > 2000 ifTrue:[Transcript show: ‘¡Cuantas clases!’] ifFalse:[Transcript show: ‘¡No son tantas las clases!’].

Transcript cr.

Resulta muy interesante analizar la implementación del los métodos True>>ifTrue:

ifFalse: y False>>ifTrue:ifFalse: para entender cómo funcionan las estructuras de control

con objetos y mensajes.

Igualmente, a los bloques también se les puede activar con argumentos. La sintaxis para

defi nir un bloque que necesita argumentos para evaluarse es la siguiente:

[:argumento1 | Expresiones].

[:argumento1 :argumento2 | Expresiones].

“Estructuras tipo IF”| número paridad |

número := 11.

(número \\ 2) = 0 ifTrue:[paridad := 0] ifFalse:[paridad := 1].

Transcript show: ‘el número ‘, número asString, ‘ tiene paridad igual a ‘, paridad asString; cr.

“Estructuras tipo IF”| número paridad |

número := 11.paridad := (número \\ 2) = 0 ifTrue:[0] ifFalse:[1].

Transcript show: ‘el número ‘, número asString, ‘ tiene paridad igual a ‘, paridad asString; cr.

“Estructura tipo WHILE”| index |index := 1.[index < 10] whileTrue:[ Transcript show: index; cr. index := index + 1 ].

“Estructuras tipo FOR”1 to: 10 do:[:index | Transcript show: index; cr].1 to: 10 by: 2 do:[:index | Transcript show: index; cr].

25 timesRepeat:[Transcript show: ‘.’].Transcript cr.

Page 21: Libro Smalltalk

40S

ProgramandoconSmalltalk

41S Programando con Smalltalk

Para activar un bloque que requiere un argumento se usa el mensaje #value:, para activar

uno que requiere dos argumentos se usa el mensaje #value:value:, y así sucesivamente para

bloques con tres o más argumentos.

“El mensaje #do: requiere un bloque con un argumento”| suma |suma := 0.#(2 3 5 7 11 13) do:[:primo | suma := suma + primo].Transcript show: suma; cr.

“Lo mismo el mensaje #collect:”| productos |productos := #(2 3 5 7 11 13) collect:[:primo | primo * primo].Transcript show: productos; cr.

Y, por último, se pueden declarar variables temporales al bloque con la siguiente sintaxis.

[| variableTemporal | Expresiones].

[:argumento1 | | variableTemporal | Expresiones].

ß Comentarios Se pueden insertar comentarios en cualquier parte del código, los cuales

han de estar encerrados entre comillas dobles. El primer comentario de un método se

considera comentario del método.

El comentario es un texto adicional que se añade al código para explicar su funcionalidad,

por lo que es parte importante de la documentación de una herramienta. Además, no

incrementa el tamaño del archivo porque es ignorado por el compilador.

ß Método de ejemplo El siguiente método de ejemplo muestra muchos de los aspectos de

la sintaxis del lenguaje Smalltalk.

“A las colecciones SortedCollection se les puede especifi car un bloque con 2 argumentos como comparador”| colección |colección := SortedCollection sortBlock:[:x :y | x size < y size].colección add: ‘un string más largo’.colección add: ‘un string’.colección add: #(#un #array #con @simbolos).Transcript show: colección; cr.

2.8 Herramientas

Un ambiente Smalltalk típico cuenta con muchas herramientas que asisten en la tarea

de desarrollo de software. Según el estilo que hemos escogido para el libro, explicaremos

las herramientas en función lo vayan requiriendo los ejemplos que desarrollamos en el

capítulo ¡Manos a la Obra!

2.9 Librería de Clases y Frameworks

La imagen de un Smalltalk cuenta con cientos, incluso miles, de clases cuyas funcionalidades

son perfectamente aprovechables para nuestro desarrollo.

métodoDeEjemplo: argumento “Este es un pequeño método que muestra varias de las partes de la sintaxis del lenguaje Smalltalk.

El método tiene envío de mensajes Unary, Binary y Keyword; declara argumentos y variables temporales; accede a una variable global; usa literales como array, character, symbol, string, integer y fl oat; usa las pseudo-variables true, false, nil, self y super; usa bloques con y sin argumentos, con y sin variables temporales al bloque; hace una asignación; devuelve un resultado al fi nalizar y, fundamentalmente, no hace nada útil.

Basado en el método encontrado en: http://wiki.cs.uiuc.edu/VisualWorks/A+small+method+that+uses+all+of+the+Smalltalk+syntax”

| variableTemporal bloqueConVariableTemporal |

true & false not & (nil isNil) ifFalse: [self halt].

variableTemporal := self size + super size.

bloqueConVariableTemporal := [ | variableTemporalAlBloque | variableTemporalAlBloque := 1. variableTemporalAlBloque := variableTemporalAlBloque + 1 ]. bloqueConVariableTemporal value.

#($a #a ‘a’ 1 1.0) do: [:each | Transcript show: (each class name); show: ‘ ‘; cr].

^ argumento < variableTemporal

2.8

Page 22: Libro Smalltalk

42S

ProgramandoconSmalltalk

43S Programando con Smalltalk

Las clases incluidas en Smalltalk nos ofrecen, entre otras cosas, la siguientes utilidades:

Números

Existen todo tipo de números (enteros, coma flotante, fracciones, etc.).

Colecciones

El framework de colecciones de Smalltalk es uno de los más antiguos y más funciona-

les que existen en la actualidad. La lista de colecciones incluye Bag, Set, OrderedCollec-

tion, SortedCollection, Dictionary, etc.

String

Soporte para cadenas de caracteres de bytes y cadenas que soportan caracteres unicode.

Boolean

Las clases Boolean, True y False se usan, entre otras cosas, para implementar algunas

de las estructuras de control.

Cronología

Clases como Date, Time, DateAndTime, Month, Week, Year,

Gráficos

Smalltalk está muy relacionado con el desarrollo de las interfaces de usuario gráfi-

cas. En los diversos ambientes de Smalltalk completamente auto-contenidos (como

Squeak), todo lo referente al procesamiento gráfico está implementado en el mis-

mo Smalltalk y, por ende, se puede inspeccionar y modificar por el usuario. Así,

se cuenta con operaciones 2D básicas (como BitBtl) hasta soporte para gráficos

3D con OpenGL. Squeak, a sía de hoy, tiene soporte para colores con el canal alfa

(transparencia), anti-aliasing, renderizado de TTF (True Type Fonts), etc.

Stream

En algunas ocasiones es necesario combinar operaciones de acceso a los elementos

de una colección con operaciones de inserción de elementos. Los típicos mensajes de

enumeración de las colecciones de Smalltalk no permiten insertar elementos mien-

tras se lleva a cabo la iteración. La jerarquía de clases de Stream permite la iteración

(repetición de una secuencia de instrucciones) de colecciones a la vez que la inserción

de elementos. La metáfora de los streams de objetos funcionó tan bien en Smalltalk

que, a partir de entonces, se usa para acceder a fuentes de datos externas en el ambien-

te y en muchos lenguajes orientados a objetos.

Weak References

Se puede hacer un uso avanzado del recolector de basura (mecanismo implícito

de gestión de memoria) utilizando referencias débiles a objetos. Las referencias

débiles, al contrario de las referencia normales o fuertes, no evitan que un objeto

sea reclamado por el recolector. Un objeto puede ser requerido por el recolector

cuando no tenga referencias en absoluto, o sólo tenga referencias débiles. Resulta

muy útil para implementar cachés, pool de instancias, mecanismos de finalización

de objetos, etc.

Multithreading

Smalltalk soporta multithreading desde los inicios. Se cuenta con una rica variedad

de clases para hacer programación concurrente de forma sencilla. Las clases Process

(Proceso = Thread) y Semaphore (Semáforo) sirven de base para la programación

con threads.

ExcepcioneS

Smalltalk cuenta con un moderno esquema de excepciones. A diferencia de otros

lenguajes, toda la implementación de excepciones está escrita en el mismo lenguaje.

Entre otras cosas, el mecanismo de excepciones de Smalltalk permite continuar con

la ejecución en el punto siguiente donde se produjo la excepción.

Metaclases

Todo en Smalltalk es un objeto. Todos los objetos tienen una clase y, las clases, como

todo, son objetos. Las clases, a su vez, tienen su clase, que se llama Metaclase. Todo el

mecanismo de herencia está modelado con clases y metaclases.

Page 23: Libro Smalltalk

44S

ProgramandoconSmalltalk

45S

Seaside

Es un framework para hacer aplicaciones web basado en continuations. Un framework

como Seaside simplifi ca muchísimo el manejo del fl ujo de un sitio web.

SUnit

Éste es el framework del que derivan todos los frameworks de unit-testing que existen.

Magma

Base de datos de objetos, multiusuario, que permite una completa transparencia a la

hora de persistir objetos.

2.10 Máquina Virtual

Recordemos que la máquina virtual (virtual machine - VM) permite ejecutar distintos

sistemas operativos simultáneamente sobre el mismo hardware.

La máquina virtual de Squeak está escrita en Smalltalk. El truco consiste en la utilización de

un subconjunto del lenguaje Smalltalk que puede ser traducido a lenguaje C y compilado

para la plataforma necesaria. Esto permite, entre otras cosas, un nivel de portabilidad muy

alto que convierte a Squeak en una de las piezas de software más portable contando, a día

de hoy, unas 25 plataformas diferentes.

Todo el proceso de depuración de la máquina virtual puede hacerse en Squeak, lo que

facilita mucho la investigación con arquitecturas de VM diferentes, extensiones, etc.

La VM de Squeak, en el momento de escribir este libro, es de 32 bits (aunque ya exista una

VM de 64 bits) y cuenta con un recolector de basura (garbage collector) generacional de

muy altas prestaciones.

2.10 OBRA !CAPÍTULO 3CAPÍTULO 3

En este capítulo ya nos vamos a introducir de lleno en la programación con Smalltalk.

Veremos cómo aprender a programar en este entorno trasciende al mero aprendizaje de

una sintaxis y una librería de clases. Digamos que es mucho más importante saber cómo

utilizar el entorno para nuestro benefi cio y cómo trabajar con un ambiente de objetos

vivos.

Smalltalk no es sólo un lenguaje de programación, sino que también es un entorno donde

conviven objetos que interactúan entre sí mediante el envío de mensajes. Por tanto, toda la

programación se desarrolla como el resultado del envío de mensajes a los objetos. Cuan-

do un usuario interactúa con un ambiente Smalltalk, éste último se ve modifi cado como

efecto de esa interacción.

Recordemos que en Smalltalk todo es un objeto. Tanto las clases como los métodos tam-

bién son objetos, por lo que, para impactar sobre ellos, debemos enviarles mensajes. Esto

implica que la programación no es diferente a cualquier otra tarea que se haga en un en-

torno Smalltalk: objetos que reciben mensajes y que reaccionan como efecto de ese envío.

Manual de referencia

MANOS A LA!

Page 24: Libro Smalltalk

“Cambiar el color al Mundo” World color: Color lightYellow muchLighter. World color: Color white.

“El Mundo se oscurece por un instante” World fl ash.

“Juguemos con el borde del Mundo” World borderWidth: 4. World borderColor: Color red.

Figura 2

SS

S

Figura 3

46S

ProgramandoconSmalltalk

47S Manos a la obra

En Smalltalk no existe diferencia entre desarrollo y ejecución, sino que la programación se

hace modifi cando objetos mientras estos están en funcionamiento. Para ilustrar mejor esta

idea vamos a desarrollar, paso a paso, tres ejemplos sencillos que también nos servirán para

tomar un primer contacto con las principales herramientas de desarrollo en Smalltalk.

3.1 Modifi cando objetos vivos

Vamos a crear una clase, de nombre

Cliente, que será la representación en

nuestro entorno de los clientes reales

de un supuesto sistema de factura-

ción. Para esto utilizaremos una de las

herramientas que nos ofrece Smalltalk

para interactuar con el ambiente: el

Browser de Clases.

Esta opción la encontraremos acti-

vando el menú del Mundo de Squeak

con un clic y seleccionando la opción

open... para obtener el submenú de la

Figura 1.

El Mundo

El objeto gráfi co que contiene a todos los demás objetos se llama Mundo. El Mundo

de Squeak es similar al escritorio de los sistemas operativos actuales, pero respetan-

do la regla básica de Smalltalk: todo es un objeto.

Por tanto, el Mundo es un

objeto y disponemos de

una variable global lla-

mada World para acce-

der a él. Podemos evaluar

algunas de las siguientes

sentencias para ver cómo

reacciona el Mundo:

A continuación seleccionamos la op-

ción browser (b), tal y como vemos en

la Figura 2.

Y obtenemos el Browser de Clases, cuya

apariencia es la que podemos ver en la

Figura 3.

Browser de Clases

Esta herramienta nos permite ver y modifi car todas las clases que tenemos en nues-

tro entorno. Además, también tenemos la posibilidad de crear o eliminar Categorías

de Clases, Clases, Categorías de Métodos y Métodos.

Como Squeak está escrito en sí mismo, a través de esta utilidad podemos ver abso-

lutamente todo su funcionamiento, desde el compilador hasta las ventanas, desde los

números enteros hasta los tipos booleanos, todo es visible y todo es modifi cable.

S

Figura 1

S

Figura 1

S

Figura 2

SSS

Page 25: Libro Smalltalk

Figura 4Figura 4

S

Figura 5Figura 5

SFigura 6Figura 6

S48S

ProgramandoconSmalltalk

49S Manos a la obra

Tipos de Browser de Clases

El Browser está compuesto principalmente por 4 paneles superiores y un panel inferior. En

los paneles superiores encontraremos, de izquierda a derecha, las Categorías de Clases, las

Clases, las Categorías de Métodos y los Métodos, tal como se indica en la Figura 4.

Existen diferentes tipos de Browser de Clases, sin embargo, prácticamente todos

comparten la funcionalidad básica. En este manual usaremos el Refactoring Browser

que, además de brindarnos las características del Browser básico, nos ofrece opciones

para la refactorización del código ( concepto que veremos más adelante).

Tanto las Categorías de Clases como las Categorías de Métodos no tienen una se-

mántica para Smalltalk en sí mismo, sino que sirven para documentar el diseño

agrupando clases y métodos por funcionalidad para facilitar al usuario el manejo

del sistema.

En Smalltalk se lee mucho más código del que se escribe, por lo que todo el entorno

promueve la escritura de código limpio y documentado, viéndose recompensado

así el tiempo que utilicemos en la programación.

Categorías de Clases y Métodos

Bien, si seleccionamos una de las opciones del panel, en los paneles subsiguientes veremos

la información correspondiente a la selección. Por ejemplo, si elegimos en el primer panel

la categoría de clases Kernel-Objects, en el segundo panel tendremos las clases dentro de

esa categoría como Boolean, DependentsArray, False, MessageSend, etc. De la misma

forma, si ahora seleccionamos la clase Boolean en el segundo panel, en el tercero veremos

las categorías de métodos de esa clase; y si elegimos una categoría de métodos como con-

trolling, obtendremos los métodos en el último panel. Por último, si seleccionamos uno de

los métodos, veremos en el panel inferior el código de dicho método (ver Figura 5).

Ahora vamos a crear una categoría de clases para incluir dentro la nuestra, Cliente. Para

conseguir esto, pedimos el menú contextual, haciendo clic con el botón azul del ratón, del

panel de Categorías de Clases y seleccionamos la opción add item...( ver Figura 6). S

Page 26: Libro Smalltalk

Figura 7Figura 7

S

Figura 8Figura 8

S

50S

ProgramandoconSmalltalk

51S Manos a la obra

Squeak es multiplataforma y a día de hoy funciona en más de 20 plataformas

diferentes: GNU/Linux, varios sabores de Unix, Windows, Apple, PDA como iPaq

y un largo etcétera. Sin embargo, esta variedad conlleva algunos problemas como,

por ejemplo, el uso de los distintos tipos de ratones que posee cada una de ellas.

Por motivos históricos que se remontan al ratón de la computadora Xerox Alto, a

los 3 botones del ratón se les nombra con colores: Rojo, Amarillo y Azul.

Botón Rojo:

El Botón Rojo es el que se usa para seleccionar. En prácticamente todas las plata-

formas este botón se mapea al botón principal de la plataforma (normalmente, el

botón izquierdo del ratón, o el tap del lápiz).

Botón Amarillo:

El Botón Amarillo se utiliza para pedir el halo de los objetos gráfi cos. En GNU/Li-

nux se utiliza el botón derecho, en Windows el botón del medio o ALT-clic y, en

Apple, Opt-clic.

Botón Azul:

El Botón Azul se usa para obtener el menú contextual. En GNU/Linux (y todos

los sabores de Unix) obtenemos el menú contextual haciendo clic con el botón del

medio del ratón, en Windows se obtiene el menú contextual con un clic del botón

derecho y, en Apple, con Cmd-clic.

A continuación tecleamos el nombre de la nueva categoría, en nuestro caso, Facturacion

(ver Figura 7).

Squeak y el Ratón Presionamos Intro o hacemos clic en el botón Accept(s) y obtenemos el resultado que

nos muestra la Figura 8.

Al crear una nueva categoría, ésta se selecciona automáticamente y en el panel inferior

aparece una plantilla (template) para crear una clase nueva. Para incluir una nueva clase

tenemos que enviarle un mensaje a la superclase, acción que podemos ejecutar a través de

la plantilla que nos ofrece el Browser de Clases. Simplemente reemplazamos NameOfSub-

class por el nombre de la clase que queremos crear (ver Figuras 9 y 10).

Ahora debemos aceptar nuestro cambio usando la opción accept (s) el menú contextual

del panel inferior, tal y como nos muestran las Figuras 11 y 12.

En Squeak el foco del teclado está en el control al que esté apuntado el puntero del

ratón. Por ello antes de teclear algo hay que asegurarse que estemos apuntando al

control con el ratón.

Foco del Teclado

Page 27: Libro Smalltalk

Figuras 9 y 10

S

S

Figura 9

Figura 10

Figura 11 Figura 11

S Figura 12

52S

ProgramandoconSmalltalk

53S Manos a la obra

El Workspace (espacio de trabajo) es una ventana que nos permite ordenar el código

que vamos evaluando de forma interactiva en nuestro entorno. Por tanto, se trata

de una herramienta importante y útil, aunque en Smalltalk se puede evaluar código

en cualquier panel de texto y no sólo en los espacios de trabajo.

Workspace

S

Page 28: Libro Smalltalk

Figura 15

Figura 13 y 14

Figura 15

Figura 13 y 14

S

Seguidamente escribimos en el re-

cién abierto Workspace la siguien-

te instrucción:

Para abrir un Workspace o Shout Workspace, de nuevo usaremos el menú del Mundo

(World) | Open... | Workspace o Shout Workspace.

Cliente new

S54S

ProgramandoconSmalltalk

55S Manos a la obra

Un Shout Workspace es un espacio de trabajo que muestra sintax-highlight (añade

colores según la semántica de la sintaxis) conforme lo utilizamos. Para este libro

usaremos esta herramienta porque es más vistosa que el Workspace tradicional. No

obstante, desde el punto de vista de funcionalidad no existe ninguna diferencia en-

tre ambas alternativas.

Lo seleccionamos con el ratón,

activamos el menú contextual y

elegimos la opción inspect it (i)

(ver Figura 15).

Tipos de Workspace

Sentencias de ejemplo para evaluar, imprimir,inspeccionar o explorar

“Algunas cositas con String” ‘un string’. ‘un string’ , ‘ concatenado a otro’. ‘un string de cierto tamaño’ size. ‘*string*’ match: ‘un string’.

“Algunos números” 34. 1 / 3. (1 / 3) asFloat. 3.141592653589793. 1000 factorial.

“Algo del Mundo” World extent. World color.

“Expresiones Booleanas” 1 > 3. true. false.

“Otras Expresiones” nil. Date today. Time now. Time millisecondsToRun: [1000 factorial].

“Algunas cositas con colecciones” Smalltalk allClasses. Smalltalk allClasses collect:[:each | each name]. Smalltalk classNames. Smalltalk classNames size. Smalltalk classNames select:[:each | ‘*String*’ match: each].

Evaluando Código

Al evaluar código Smalltalk de forma interactiva, disponemos de cuatro opciones

sobre cómo tratar la respuesta.

do it evaluar el código e ignorar la respuesta.

print it evaluar el código e imprimir por pantalla la representación

como String de la respuesta.

inspect it evaluar el código e inspeccionar el resultado. Ésta es la opción

utilizada en el ejemplo.

explore it evaluar el código y explorar el resultado. El Explorer es otro

formato de Inspector.

SS

Page 29: Libro Smalltalk

Figura 16Figura 16

S

Figura 17Figura 17

S

Figura 18Figura 18

S

Figura 19Figura 19

S56S

ProgramandoconSmalltalk

57S Manos a la obra

Esta acción nos brindará otra de las herramientas de Smalltalk: el Inspector (ver Figura 16).

El Inspector es una herramienta que nos permite ver cómo está compuesto un obje-

to, qué variables de instancia tiene y qué valores tienen estas variables de instancia.

En Smalltalk, absolutamente todos los objetos pueden ser inspeccionados.

Veamos ahora cómo está compuesto el Inspector que, como hemos dicho, nos ofrece

la posibilidad de ver un objeto por dentro y enviarle mensajes.

En el panel de las variables de instancia tenemos dos variables especiales: self y all

inst var. Al seleccionar self, en el panel de la derecha vemos la representación como

String del objeto inspeccionado. Y, si seleccionamos all inst var, vemos todas las

variables de instancia como si fuesen una sola.

Ahora vamos a modifi car ligeramente la clase Cliente, pero lo haremos sin cerrar el Inspec-

tor a la instancia. Es decir, vamos a cambiar la estructura del objeto mientras éste esté vivo.

Inspector

Así, volvemos al browse y nos aseguramos que estén seleccionadas la categoría de clase

‘Facturacion’ y la clase Cliente. Entre las comillas simples que están detrás de la palabra

instanceVariableNames tecleamos lo que vemos en la Figura 18.

Y aceptamos los cambios como lo hicimos anteriormente (menú contextual, opción

accept (s)).

Algunas de las opciones que hemos ido utilizando durante el ejemplo tienen una

letra entre paréntesis, el hot-key. Podemos invocar esas opciones presionando ALT

y la letra.

Ejemplo:

browser (b) » ALT-b

workspace (k) » ALT-k

accept (s) » ALT-s

inspect it (i) » ALT-i

explore it (I) » ALT-MAYÚSCULA-i

Si todo ha salido bien, ya deberíamos ver cómo el Inspector a la instancia de Cliente que

dejamos abierto nos muestra una nueva variable de instancia (ver Figura 19).

Hot - Keys

Figura 17

S

Page 30: Libro Smalltalk

Figura 18Figura 18

S Figura 19

xml

58S

ProgramandoconSmalltalk

59S Manos a la obra

Ahora vamos a ponerle un nombre a nuestro cliente, para lo que seleccionamos la variable

de instancia en el panel de la izquierda y, a continuación, escribimos ‘pedro’ en el panel

de la derecha:

Aceptamos los cambios (menú contextual y opción accept (s) o ALT-s), y el resultado lo

vemos en la Figura 18.

El ejemplo que acabamos de hacer deja en evidencia una diferencia fundamental de Smalltalk

respecto a los lenguajes de programación tradicionales, en los que un objeto nunca sobre-

vive a un cambio del programa. En Smalltalk es posible, y habitual, modifi car un sistema

mientras está funcionando.

Este ejemplo, además, nos ha mostrado algunas de las herramientas principales de Smalltalk

(Browser, Workspace e Inspector) de las que hemos visto su uso básico. Por tanto, ya esta-

mos preparados para pasar a un ejemplo más complejo.

‘pedro’

Para terminar este ejemplo saldremos de nuestro

entorno grabando todos los cambios. Para ello,

abrimos el menú del Mundo (Word) y escogemos

la opción save and quit ( ver Figura 19).Cuando

entremos nuevamente a nuestro Smalltalk, ten-

dremos todo el entorno en el mismo estado en que

lo dejamos.

3.2 Parser de XML basado en una Pila

Para procesar archivos XML, tarea que realizaremos en el próximo ejemplo, usaremos una

herramienta que simplifi ca mucho la escritura de parsers de XML. El parser que utilizare-

mos funciona de la siguiente manera: cada vez que éste encuentra un nuevo tag de XML,

envía un mensaje al objeto que está más arriba en su pila y el resultado del envío se apila.

Cuando ese mismo tag termina, el objeto se desapila. El primer objeto apilado es uno

escrito manualmente, y es el que procesará los tags de más alto nivel. El mensaje que se

envía al objeto superior de la pila tiene como parámetro un diccionario que contiene los

atributos del tag.

Veamos un ejemplo lo sufi cientemente simple como para analizarlo por completo. Imagi-

nemos un archivo XML como el siguiente:

Este archivo contiene los datos de una agenda, la cual tiene dentro personas y las personas

direcciones y datos de contacto y, a su vez, las informaciones de contacto tienen teléfonos

y direcciones de email.

A continuación, instruimos al parser para que envíe los siguientes mensajes según el tag

que se procese:

3.2

<agenda>

<persona apellido=”Gates” nombre=”Bob”>

<direccion ciudad=”Los Angeles” numero=”1239” provincia=”CA” calle=”Pine Rd.”/>

</persona>

<persona apellido=”Smith” nombre=”Joe”>

<informacion-contacto>

<email direccion=”[email protected]”/>

<telefono numero=”888-7657765”/>

</informacion-contacto>

<direccion ciudad=”New York” numero=”12789” provincia=”NY” calle=”W. 15th Ave.”/>

</persona>

</agenda>

Tag de XML Mensaje a Enviar

<agenda> #crearAgenda:

<persona> #crearPersona:

<direccion> #crearDireccion:

<informacion-contacto> #crearInformacionContacto:

<email> #crearEMail:

<telefono> #crearTelefono:

Page 31: Libro Smalltalk

una AgendasLa pila del parser contendrá,

por tanto, lo siguiente:

una Agenda

una Agendas

60S

ProgramandoconSmalltalk

61S Manos a la obra

Antes de comenzar el parseo, incluiremos en la pila el objeto Agendas. Ese objeto es ca-

paz de crear y almacenar agendas, es decir, posee la capacidad de responder al mensaje

#crearAgenda:

Como el resultado de la evaluación del mensaje #crearAgenda: es una Agenda, ésta se apila

y es ahora la responsable de contestar al mensaje #crearPersona:

Agendas>>crearAgenda: aDictionary “Crea una nueva agenda y la guarda en el receptor” | agenda | agenda := Agenda new. self addAgenda: agenda. ^ agenda.

Smalltalk con Estilo

En Smalltalk existe un idioma que consiste en nombrar a los objetos con a o an

(uno o una en inglés) y el nombre de la clase.

De esa forma, a una instancia de la clase String se le llama aString o a String, una

instancia de Date se llama aDate o a Date, una instancia de Integer es anInteger o

an Integer, etc.

El lugar ideal para conocer todas las convenciones e idiomas que se usan en Small-

talk es el libro “Smalltalk with Style” (ver bibliografía).

NombreDeClase>>nombreDeMétodo

Cuando es necesario volcar el código fuente de un método en panel, se utiliza la

convención de escribirlo con el nombre de la clase, seguido de >> y, a continuación,

el nombre del método.

Esto es una convención para el papel y no es parte de la sintaxis de Smaltalk.

El método de la clase Agenda es muy similar al anterior método #crearAgenda: excepto

porque éste último considera los atributos presentes en el tag <persona>, que vienen en el

argumento aDictionary, para crear una Persona con nombre y apellido.

Bien, ahora se ha apilado una Persona, por lo que este objeto es el responsable de contestar

al mensaje #crearDireccion:

Agenda>>crearPersona: aDictionary “Crea una nueva persona y la guarda en el receptor” | persona | persona := Persona apellido: (aDictionary at: ‘apellido’) nombre: (aDictionary at: ‘nombre’). self addPersona: persona. ^ persona.

una Persona nombre=’Bob’ apellido=’Gates’

una Agenda

una Agendas

Persona>>crearDireccion: aDictionary “Crea una nueva direccion y la guarda en el receptor” | direccion | direccion := Direccion calle: (aDictionary at: ‘calle’) numero: (aDictionary at: ‘numero’) ciudad: (aDictionary at: ‘ciudad’) provincia: (aDictionary at: ‘provincia’). self addDireccion: direccion. ^ direccion.

La Direccion devuelta por el método anterior se suma a los demás objetos, dejando la pila

de la siguiente forma:

La pila, en este punto, contiene lo siguiente:

Page 32: Libro Smalltalk

62S

ProgramandoconSmalltalk

63S Manos a la obra

Llegados a este punto, el parser se enfrenta, por primera vez en este ejemplo, al cierre del

tag. Por tanto, al cerrarse el tag <direccion>, el parser desapila la dirección.

A continuación, se cierra el tag <persona>, así que se desapila la persona.

Ahora se envía otro mensaje #crearPersona: a la Agenda, creando una nueva Persona y

apilándola.

una Direccion calle=’Pine Rd.’ numero=’1239’ ciudad=’Los Angeles’ provincia=’CA’

una Persona nombre=’Bob’ apellido=’Gates’

una Agenda

una Agendas

una Persona nombre=’Bob’ apellido=’Gates’

una Agenda

una Agendas

una Agenda

una Agendas

una Persona nombre=’Joe’ apellido=’Smith’

una Agenda

una Agendas

Persona>>crearInformacionContacto: aDictionary “Crea una nueva informacion de contacto y la guarda en el receptor” ^ informacionContacto := InformacionContacto new.

Seguidamente se envía un mensaje #crearInformacionContacto: a la Persona como reac-

ción al tag <informacion-contacto>.

La pila queda ahora de la siguiente forma:

A continuación, el objeto superior de la pila (una InformacionContacto) recibe el men-

saje #crearEMail:

El resultado del método anterior (un EMail) se apila, pero inmediatamente después se

desapila puesto que el tag <email> se cierra y la Información de Contacto nuevamente

queda en la parte superior de la pila.

El tag <telefono> se procesa de forma similar al tag <email>.

A continuación se cierra el tag <informacion-contacto> y se desapila la Información de

Contacto.

Después, procesamos el tag <direccion> del mismo modo en que se procesó para la perso-

na anterior, apilando el resultado y desapilándolo en cuanto se cierra el tag.

El estado de la pila, en este punto, es el siguiente:

una Persona nombre=’Joe’ apellido=’Smith’

una Agenda

una Agendas

InformacionContacto>>crearEMail: aDictionary “Crear un nuevo email y lo guarda en el receptor” | eMail | eMail := EMail direccion: (aDictionary at: ‘direccion’). self addEMail: eMail. ^ eMail.

InformacionContacto>>crearTelefono: aDictionary “Crear un nuevo teléfono y lo guarda en el receptor” | telefono | telefono := Telefono numero: (aDictionary at: ‘numero’). self addTelefono: telefono. ^ telefono.

Page 33: Libro Smalltalk

xml64S

ProgramandoconSmalltalk

65S Manos a la obra

Y, ya estamos terminando de procesar el XML, sólo resta el cierre del tag <persona> y el

del tag <agenda>. Es decir, que se desapila la persona y, a continuación, la agenda, quedan-

do la pila en el mismo estado que estaba antes de comenzar el parseo.

Una vez explicado cómo funciona el parser de XML basado en una pila, podemos comen-

zar ya con el importador de Wikipedia.

3.3 Importador de Wikipedia

En este apartado nos ocuparemos de un ejemplo un poco más complejo y, a su vez, más

completo, hablamos de crear un importador de los datos de la Wikipedia.

una Persona nombre=’Joe’ apellido=’Smith’

una Agenda

una Agendas

una Agenda

una Agendas

3.3

Wikipedia

Wikipedia es un proyecto para escribir de manera comunitaria enciclopedias libres

en todos los idiomas. Éste fue fundado por Jimmy Wales y Larry Sanger basándose

en el concepto wiki, que permite crear colectivamente documentos web sin que sea

necesaria la revisión del contenido antes de su aceptación para ser publicado en la

Red. La versión en inglés comenzó el 15 de enero de 2001 y tres años y medio des-

pués, en septiembre de 2004, unos 10.000 editores activos trabajaban en 1.000.000

de artículos en más de 50 idiomas. Podemos obtener más información en http://

es.wikipedia.org/wiki/Wikipedia

- Archivos de la Wikipedia:

http://download.wikipedia.org

http://download.wikipedia.org/wiki/Importing_a_Wikipedia_database_dump_

into_Mediawiki

Por tanto, el proyecto Wikipedia ofrece toda la información de sus sitios disponibles para

bajar desde Internet, pudiéndose descargar todos los artículos de las distintas enciclope-

dias de diferentes idiomas en un archivo XML.

Con este concepto claro, vamos a llevar a cabo un ejemplo programando de la forma más

incremental posible, es decir, ejecutaremos todo el código que podamos en el Depurador.

Veamos un XML de ejemplo sacado de la Wikipedia en Latín, pero simplifi cado y acortado

para poder analizarlo en toda su extensión:

<mediawiki>

<siteinfo>

<sitename>Vicipaedia</sitename>

<base>http://la.wikipedia.org/wiki/Pagina_prima</base>

<generator>MediaWiki 1.6devel</generator>

<case>fi rst-letter</case>

<namespaces>

<namespace key=”-1”>Specialis</namespace>

<namespace key=”0” />

<namespace key=”1”>Disputatio</namespace>

</namespaces>

</siteinfo>

<page>

<title>Astronomia</title>

<id>1</id>

<revision>

<id>46556</id>

<timestamp>2005-10-31T22:28:43Z</timestamp>

<contributor>

<ip>80.136.214.100</ip>

</contributor>

<text>’’’Astronomia’’’</text>

</revision>

</page>

<page>

<title>Auxilium</title>

<id>2</id>

<revision>

<id>44264</id>

<timestamp>2005-10-11T16:43:35Z</timestamp>

<contributor>

<ip>217.72.33.184</ip>

</contributor>

<comment>better latin from italy [[:it:Utente:OrbiliusMagister]]</

comment>

<text>’’Hic addendae sunt notiones ad usum lectoris</text>

</revision>

Page 34: Libro Smalltalk

Figura 22Figura 22

SFigura 24Figura 24

S66S

ProgramandoconSmalltalk

67S Manos a la obra

Observamos que

un <mediawiki>

contiene <sitein-

fo> y <page>, que

los <page> inclu-

yen <revision> y

que las <revision>

tienen el texto de

las páginas.

Del mismo modo,

vemos que algu-xml

</page>

<page>

<title>Usor:Archibald Fitzchesterfi eld</title>

<id>3</id>

<revision>

<id>25286</id>

<timestamp>2002-11-26T18:33:53Z</timestamp>

<contributor>

<ip>host155-164.pool21345.interbusiness.it</ip>

</contributor>

<comment>*</comment>

<text>Studiosus sum in Universitate Torontoniense</text>

</revision>

</page>

</mediawiki>

Las clases en Smalltalk son, obviamente, también objetos. Así, la clase modela las

instancias y, la clase de la clase (la metaclase), modela la clase.

Las clases reciben mensajes (como cualquier objeto) y los métodos de clase son la

forma de responder a esos mensajes.

Por ejemplo: en Smalltalk, los constructores no tienen una semántica especial

(como sí la tienen en Java, C++, etc), aquí son simplemente métodos de clase que

tienen la responsabilidad de crear instancias.

También es frecuente encontrarse, en la clase, con métodos que operen sobre

todas las instancias de la clase, por ejemplo: #allInstances, #allSubInstances, #inspectAllInstances, etc.

Métodos de Clase vs. Métodos de Instancia

nos tags se usan

sólo para meter datos en forma de String (<sitename>, <base>, <generator>, <case>,

<namespace>, <title>, <id>, <timestamp>, <ip>, <text>, <comment>, etc). Para estos

casos, el parser nos ofrece otra forma de procesar el tag, así, defi nimos un text-tag que pro-

vocará que el objeto superior de la pila reciba un mensaje con un String como argumento

con el texto del tag, apilándose igualmente.

Con este ejemplo pretendemos mostrar las facilidades que nos brinda Smalltalk para la

programación incremental. Y, dicho esto, ya hemos analizado demasiado el XML antes de

comenzar. Empecemos.

Lo primero que tenemos que hacer es instar al parser e incluirle la información básica para

empezar a programar. Así, creamos una clase Mediawiki que incluya unos métodos de

clase para instanciar Mediawikis desde archivos XML.

Para esto, abrimos un Browser de Clases (menú del Mundo | open... | browser (b) o ALT-

b). A continuación, creamos una categoría de clases para incluir nuestra clase dentro. Para

conseguirlo, pedimos el menú contextual (haciendo clic con el botón azul del ratón) del

panel de Categorías de Clases y seleccionamos la opción add item... (ver Figura 22).

Seguidamente, tecleamos el nom-

bre de nuestra categoría de clases,

tal y como vemos en la Figura 23.

Aceptamos y obtenemos el resulta-

do que nos muestra la Figura 24.

Figura 23Figura 23

S

Page 35: Libro Smalltalk

Figura 25Figura 25

SFigura 26Figura 26

S

Figura 27Figura 27

S

Figura 29Figura 29

S68S

ProgramandoconSmalltalk

69S Manos a la obra

Ya estamos listos para crear la primera clase de nuestro ejemplo. Para ello, reemplazamos

la orden NameOfSubclass por el nombre de la clase que queremos crear, en este caso,

Mediawiki (ver Figura 25).

Aceptamos y obtenemos el siguiente resultado (ver Figura 26 y Figura 27).

Para crear métodos de clase en lugar de métodos de instancia, debemos seleccionar el bo-

tón class, que está debajo del panel de Clases. Cuando lo hagamos, los otros dos paneles

mostrarán categorías de métodos de clase en lugar de instancia. En el caso que queramos

volver a modifi car o ver categorías de métodos de instancia, no hay más que presionar el

botón instance (ver Figura 28).

Volvemos, entonces, al botón class y creamos una categoría de métodos (de clase, en este

caso) llamada instance creation con la opción new category... del menú contextual del

panel de Categorías de Métodos y, seguidamente, elegimos la categoría entre las opciones

disponibles (ver Figura 29).

Una vez tenemos nuestra clase creada, haremos lo mismo con los métodos de clase, a

modo de constructores, para instanciar Mediawikis desde archivos XML.

Page 36: Libro Smalltalk

Figura 29Figura 29

SFigura 29Figura 30Figura 30

S

Figura 31Figura 31

S

70S

ProgramandoconSmalltalk

71S Manos a la obra

Si todo ha ido bien, la recién creada categoría de métodos (de clase) quedará seleccionada

y el browser nos ofrecerá una plantilla para crear un método dentro de esa categoría en el

panel inferior, tal y como vemos en la Figura 30.

fromFileNamed: aString “Crea una nueva instance del receptor desde el archivo llamado aString”

| archivo instancia parser |

“abre el archivo” archivo := FileStream readOnlyFileNamed: aString.

“crea la instancia del receptor” instancia := self new.

“instancia el parser” parser := XMLStackParser on: archivo.

“la instancia recién creada es el primer objeto de la pila” parser push: instancia.

“instruimos al parser sobre como procesar el tag <mediawiki>” parser onTag: ‘mediawiki’ send: #onMediawiki:.

“le pedimos al parser que haga su trabajo” parser parseDocument.

“cerramos el archivo” archivo close.

“devolvemos la instancia al remitente del mensaje” ^ instancia

A continuación, ejecutamos las siguientes órdenes en el panel inferior y aceptamos:

El Browser de Clases nos ofrece una plantilla que podemos utilizar para crear nuevos

métodos.

Plantilla para nuevos métodos

Figura 29

SS

Page 37: Libro Smalltalk

Figura 33Figura 33

S

Archivos de ejemplo

pre-Depurador

72S

ProgramandoconSmalltalk

73S Manos a la obra

Ahora, ya estamos en condiciones de ejecutar, por primera vez, nuestro importador de

Wikipedia. Abrimos un Workspace a través del menú del Mundo | open... | Shout Work-

space y tecleamos lo que aparece en la Figura 32.

El archivo tiny.xml y otros archivos usados en este libro se pueden descargar desde http://wiki.gnulinex.org/LibroProgramacionSmalltalk/

El archivo tiny.xml contiene exactamente el texto expuesto en la página 22.

Ahora seleccionamos la sentencia que acabamos de escribir y la evaluamos con do it (d)

o ALT-d. Veremos que, por primera vez, aparece un error (ver Figura 23). ¡Bienvenido al

maravilloso y dinámico mundo de Smalltalk!

El pre-Depurador es una herramienta que nos ofrece información sobre los errores

que se hayan producido, además de permitirnos ejecutar alguna acción para subsa-

nar el problema (ver Figura 34).

Los errores de cualquier tipo siempre pueden hacernos refl exionar sobre nuestro siste-

ma, aparte de permitirnos re-validar nuestras concepciones sobre el dominio que estamos

modelando.

El título de la ventana muestra el tipo de error, en este caso, es un típico MessageNot-

Understood (Mensaje No Entendido). Es decir, el pre-Depurador nos está indican-

do que algún objeto no supo cómo responder a un determinado mensaje. Si segui-

mos analizando un poco más, veremos que el objeto en cuestión es un Mediawiki y

el mensaje que no entiende es #onMediawiki:

Esta ventana nos ofrece varias alternativas para procesar el error:

Proceed: continuar con la ejecución ignorando el error.

Adandon: abandonar la ejecución.

Debug: depurar el error con el depurador “completo”.

Create: crear el método que falta en la clase del objeto receptor o en alguna

de sus superclases. Esta opción sólo aparece ante los errores del tipo Message-

NotUnderstood.

Figura 32Figura 32

SFigura 34Figura 34

S

Page 38: Libro Smalltalk

Figura 35Figura 35

SSDepurador

74S

ProgramandoconSmalltalk

75S Manos a la obra

Si analizamos la información que nos da el pre-Depurador, es fácil entender que lo que su-

cede es que al parser le hemos dado la orden de enviar el mensaje #onMediawiki: cuando

encuentre un tag <mediawiki>. De esta manera, el parser se lo envía al objeto superior de

la pila, es decir, a nuestro objeto Mediawiki.

Ahora, vamos a utilizar una de las acciones que nos ofrece el pre-Depurador, la opción de

crear el método, para lo que presionamos sobre el botón Create y obtenemos lo siguiente

(ver Figura 35):

Según observamos en la Figura 34, el pre-Depurador nos ofrece la posibilidad de crear

el método en la clase del objeto receptor o en cualquiera de sus superclases. En este caso

elegimos la clase Mediawiki.

A continuación, Squeak nos pregunta en qué categoría de métodos queremos crear el

nuestro (ver Figura 36).

Figura 36Figura 36

SComo ninguna de las categorías ofrecidas sirve para nuestro cometido, seleccionamos la

opción new... y creamos la categoría de métodos parsing (Ver Figura 37).

Figura 37Figura 37

SBien, tenemos ya el Depurador, una herramienta con la que pasaremos gran parte del

tiempo programando en Smalltalk.

El Depurador permite, por un lado, examinar cómo se desarrolla la ejecución

del código de Smalltalk y, por otro, modifi car los métodos on-the-fl y y seguir el

proceso desde el punto anterior al método modifi cado. (ver Figura 38).

El Depurador es, tal vez, una de las herramientas que más opciones nos ofrece,

entre ellas: ver la pila de contextos (que forman el call-stack), ver y modifi car

los métodos involucrados en la ejecución, inspeccionar los objetos receptores,

analizar los contextos de ejecución, ver el valor de las variables temporales y los

argumentos, evaluar el código paso a paso, etc.

Page 39: Libro Smalltalk

Figura 38Figura 38

SFigura 39Figura 39S

Depurador 100% en Smalltalk

76S

ProgramandoconSmalltalk

77S Manos a la obra

Además, a través de las siguientes funciones del Depurador, incluso podemos pro-

cesar el error (ver Figura 39).

Proceed: continuar con la ejecución ignorando el error.

Restart: reiniciar la ejecución desde el punto seleccionado en la pila de contextos.

Si el contexto seleccionado no es el superior de la pila, los que están encima de él

se descartan.

Into: seguir depurando y ver el contexto que genera el mensaje que se va a enviar.

Over: seguir depurando, pero se ignoran los detalles del envío del mensaje que se

va a enviar.

Through: continuar con la ejecución y detenerse en la primera sentencia del si-

guiente bloque.

Full Stack: ver la pila de contextos completa y no la versión reducida que se muestra

por defecto.

Where: volver a resaltar el mensaje que se está enviando.

Este Depurador está escrito en Smalltalk donde, insistimos, todo es un objeto. Tanto

las clases como los métodos y los contextos de ejecución también son objetos, por

lo que es totalmente posible escribir un Depurador 100% en Smalltalk.

Así pues, podemos llevar a cabo las mismas acciones que con el resto de los objetos.

Por ejemplo, podemos grabar la imagen con un Depurador abierto y, cuando vol-

vamos al entorno de Squeak, seguir depurando el código exactamente en el mismo

punto donde lo dejamos, aunque pasen meses desde que grabamos la imagen y la

volvemos a abrir.

Bien, el Depurador se abre en ese punto porque la implementación del método que se creó

por defecto contenía un error indicando que tenía que completarse.

Ahora vamos a ejecutar la implementación de este método, que tiene “truco“. Un objeto

de clase Mediawiki recibió el mensaje #onMediawiki: que, en teoría, debería crear un

Mediawiki. Como el tag <mediawiki> sólo aparece una vez en el archivo (por lo que sólo

recibiremos un mensaje #onMediawiki:), simplemente ignoramos el tag y devolvemos el

mismo objeto para su apilación.

S

Page 40: Libro Smalltalk

Figura 40Figura 40

S

Figura 42Figura 42

S78S

ProgramandoconSmalltalk

79S Manos a la obra

Tecleamos la siguiente instrucción en el panel que muestra el código del método del Depu-

rador y aceptamos los cambios (menú contextual y opción accept (s) o ALT-s).

El Depurador se nos mostrará con la apariencia que vemos en la Figura 40.

A continuación, presionamos el botón Proceed y seguimos con el desarrollo (ver Figura 41).

Figura 41Figura 41

SAhora, si todo ha ido bien, el parser nos va a indicar que no sabe qué hacer con el tag <si-

teinfo>, puesto que no le hemos dado ninguna orden de cómo actuar con los tags que no

sean <mediawiki>.

onMediawiki: aDictionary “No tiene sentido crear un Mediawiki si somos un Mediawiki”

^ self

parser onTag: ‘siteinfo’ send: #onSiteinfo:.

Seguidamente, pedimos el Depurador con el botón Debug y seleccionamos, en la pila de con-

textos, el que corresponde con nuestro método Mediawiki class>>fromFileNamed: (por el

que instruimos al parser para que procese cada tag), tal y como vemos en la Figura 42.

A continuación, en este mismo contexto, agregamos la siguiente secuencia:

Page 41: Libro Smalltalk

Figura 43Figura 43

SFigura 44Figura 44

S80S

ProgramandoconSmalltalk

81S Manos a la obra

Para ganar más tiempo podemos teclear las siguientes órdenes para varios tags, quedando

el método completo de la siguiente manera:

fromFileNamed: aString

“Crea una nueva instance del receptor desde el archivo llamado aString”

| archivo parser instancia |

“abre el archivo”

archivo := FileStream readOnlyFileNamed: aString.

“crea la instancia del receptor”

instancia := self new.

“instancia el parser”

parser := XMLStackParser on: archivo.

“la instancia recién creada es el primer objeto de la pila”

parser push: instancia.

“instruimos al parser sobre como procesar el tag <mediawiki>”

parser onTag: ‘mediawiki’ send: #onMediawiki:.

parser onTag: ‘siteinfo’ send: #onSiteinfo:.

parser onTag: ‘namespaces’ send: #onNamespaces:.

parser onTag: ‘namespace’ send: #onNamespace:.

parser onTag: ‘page’ send: #onPage:.

parser onTag: ‘revision’ send: #onRevision:.

parser onTag: ‘contributor’ send: #onContributor:.

“le pedimos al parser que haga su trabajo”

parser parseDocument.

“cerramos el archivo”

archivo close.

“devolvemos la instancia al remitente del mensaje”

^ instancia

Aceptamos los cambios y el Depurador quedará como vemos en la Figura 43.

Es interesante que veamos qué ha pasado con la pila de contextos después que hemos acep-

tado los cambios. Pues bien, el Depurador se ha deshecho de los contextos que estaban por

encima del método modifi cado, así que ya podemos presionar el botón Proceed que nos

permitirá seguir con la ejecución desde el método cambiado (ver Figura 44).

Page 42: Libro Smalltalk

Figura 45Figura 45

S

Figura 46Figura 46

SFigura 47Figura 47

S

Convención de nombres

82S

ProgramandoconSmalltalk

83S Manos a la obra

A continuación, el entorno nos dice que nuestro Mediawiki no sabe cómo contestar al

mensaje #onSiteinfo:, por lo que creamos el método siguiendo el mismo procedimiento

que utilizamos para crear el método #onMediawiki:

Para ello, presionamos el botón Create, seleccionamos la clase Mediawiki, la categoría de

métodos parsing y obtenemos el Depurador de la forma que vemos en el Figura 45.

Ahora, escribimos la siguiente instrucción:

onSiteinfo: aDictionary “Crea un SiteInfo y lo guarda en el receptor” siteInfo := SiteInfo new. ^ siteInfo

Antes de aceptar, observamos que el sintax-highlight, con el color rojo, nos está indicando

que desconoce qué es siteInfo y SiteInfo, variable de instancia y clase, respectivamente.

Aceptamos y vemos cómo reacciona el entorno (ver Figura 46):

Los nombres de variables de instancia, los argumentos y las variables temporales, por defecto, comienzan por una letra minúscula. Igualmente, las variables de clase, las globales y los nombres de clases comienzan por letra mayúscula.

Un sitio de referencia donde pueden consultarse todas las convenciones e idiomas usados en Smalltalk es el libro “Smalltalk with Style” (ver bibliografía).

Bien, parece que desconoce una variable llamada siteInfo, por lo que nos ofrece dos al-

ternativas: crear una variable temporal o crear una variable de instancia. En nuestro caso,

elegimos la segunda opción, cuyo resultado lo vemos en la Figura 47.

Ahora, el entorno nos comunica que tampoco conoce SiteInfo, ofreciéndonos varias op-

ciones. En el primer grupo (las tres que están antes de la primera línea) nos propone crear

una clase, una variable global o una variable de clase. En el segundo grupo de opciones

considera que cometimos un error al teclear y nos ofrece alternativas parecidas a lo que es-

cribimos nosotros, pero válidas. Y, fi nalmente, nos da la opción de cancelar la operación.

Page 43: Libro Smalltalk

Figura 49Figura 49

S

Figura 48Figura 48

S

Figura 50Figura 50

SFigura 51Figura 51

S84S

ProgramandoconSmalltalk

85S Manos a la obra

Nosotros queremos crear una nueva clase, así que seleccionamos la opción defi ne new

class. Al hacerlo, Squeak nos pregunta en qué categoría de clases queremos incluirla, así

que elegimos Squeakpedia (ver Figura 48).

Al aceptar, el entorno nos muestra el mensaje que va a enviar para crear la clase, pudiendo

modifi car algo si lo deseamos, tal y como vemos en la Figura 49:

Pero aceptamos la plantilla sin introducir cambio alguno (ver Figura 50).

A continuación, el Depurador nos muestra el método recién aceptado y el sintax-highlight

nos confi rma que siteInfo y SiteInfo ya son términos conocidos. Del mismo modo, vemos

en el Inspector del receptor (los dos paneles inferiores, a la izquierda) que hay una nueva

variable de instancia. Y, si además tenemos un Browser de Clases abierto con la categoría de

clases Squeakpedia seleccionada, veremos que también aparece una nueva clase.

Es importante remarcar que se han ejecutado la creación de métodos, la creación de va-

riables de instancia y la creación de una nueva clase mientras estábamos depurando la

aplicación, es decir, modifi camos el entorno a la vez que lo estamos usando.

En este momento, a nuestro autor le gustaría decir: “prueben esto en su lenguaje de preferen-

cia”, pero no sería políticamente correcto, así que sigamos.

Continuando con el ejemplo, ahora presionamos sobre el botón Proceed para seguir eje-

cutando la aplicación, tal y como vemos en la Figura 51.

Ahora el parser nos indica que no sabe cómo manejar el tag <sitename>. Si analizamos

el XML de ejemplo, vemos que ese tag se usa para contener un texto. Bien, el parser nos

Page 44: Libro Smalltalk

Figura 52Figura 52

S86S

ProgramandoconSmalltalk

87S Manos a la obra

permite manejar estos casos de forma especial, así que le decimos que <sitename> es un

textTag. Después, pedimos el Depurador (presionando el botón Debug) y elegimos el mé-

todo Mediawiki class>>fromFileNamed: añadiendo lo siguiente:

Y ya que estamos metidos en faena, podemos completar algunos text-tags más dejando el

método de la siguiente manera:

“instruimos al parser como procesar los text-tags” parser onTextTag: ‘sitename’ send: #siteName:.

fromFileNamed: aString “Crea una nueva instance del receptor desde el archivo llamado aString”

| archivo parser instancia |

“abre el archivo” archivo := FileStream readOnlyFileNamed: aString.

“crea la instancia del receptor” instancia := self new.

“instancia el parser” parser := XMLStackParser on: archivo.

“la instancia recién creada es el primer objeto de la pila” parser push: instancia.

“instruimos al parser sobre como procesar el tag <mediawiki>” parser onTag: ‘mediawiki’ send: #onMediawiki:. parser onTag: ‘siteinfo’ send: #onSiteinfo:. parser onTag: ‘namespaces’ send: #onNamespaces:. parser onTag: ‘namespace’ send: #onNamespace:. parser onTag: ‘page’ send: #onPage:. parser onTag: ‘revision’ send: #onRevision:. parser onTag: ‘contributor’ send: #onContributor:.

“instruimos al parser como procesar los text-tags” parser onTextTag: ‘sitename’ send: #siteName:. parser onTextTag: ‘base’ send: #base:. parser onTextTag: ‘generator’ send: #generator:. parser onTextTag: ‘case’ send: #case:. parser onTextTag: ‘namespace’ send: #name:. parser onTextTag: ‘title’ send: #title:. parser onTextTag: ‘id’ send: #id:. parser onTextTag: ‘timestamp’ send: #timestamp:. parser onTextTag: ‘ip’ send: #ip:. parser onTextTag: ‘text’ send: #text:. parser onTextTag: ‘comment’ send: #comment:.

Aceptamos los cambios y la ventana del Depurador queda ahora como vemos en la Figura 52.

“le pedimos al parser que haga su trabajo” parser parseDocument.

“cerramos el archivo” archivo close.

“devolvemos la instancia al remitente del mensaje” ^ instancia

Page 45: Libro Smalltalk

Figura 55Figura 55

S

Figura 56Figura 56

SFigura 57SFigura 57

S88S

ProgramandoconSmalltalk

89S Manos a la obra

De nuevo, estamos listos para continuar presionando el botón Proceed (ver Figura 53).

Elegimos crear un método (pulsando sobre Create) en la clase SiteInfo, tal y como vemos

en la Figura 54.

Y, seguidamente, dentro de la categoría de métodos accessing (ver Figura 55).

Ahora tenemos que implementar el método en el Depurador, tal y como lo hicimos ante-

riormente (ver Figura 56).

Para ello, escribimos la siguiente instrucción:

siteName: aByteString “Cambia el siteName del receptor” siteName := aByteString

De nuevo, el sintax-highlight nos indica, a través del color rojo, que desconoce siteName.

Bien, aceptamos los cambios y, ante la pregunta, escogemos crear una variable de instan-

cia, como vemos en la Figura 57.

Figura 53Figura 53

SFigura 54Figura 54

SFigura 55

S

Page 46: Libro Smalltalk

Figura 58Figura 58

S

Figura 59Figura 59

S

90S

ProgramandoconSmalltalk

91S Manos a la obra

Después de esto, continuamos el proceso pulsando sobre el botón Proceed.

Ahora implementamos el método #base: de la misma forma que lo hemos hecho reciente-

mente con el método #siteName:, creando también una variable de instancia:

y continuamos presionando sobre Proceed.

Del mismo modo, repetimos el proceso para el método generator:

y para el método case:

Sin embargo, vamos a detenernos y prestar más atención para el método #onNamespa-

ces: (ver Figura 58).

Empezamos creando el método en la clase SiteInfo dentro de una nueva categoría llama-

da parsing, tal y como vemos en la Figura 59.

base: aByteString “Cambia el base del receptor” base := aByteString

generator: aByteString “Cambia el generator del receptor” generator := aByteString

case: aByteString “Cambia el case del receptor” case := aByteString

Si analizamos el XML de ejemplo, veremos que el tag <namespaces> (en plural) contiene

varios tags <namespace> (en singular), así que necesitamos una colección para poder

guardar los distintos namespace que contiene un Mediawiki.

Dicho esto, implementamos el método de la siguiente manera (creando la variable de ins-

tancia namespaces cuando nos pregunte):

onNamespaces: aDictionary “Crea una colección vacía donde guardar los namespaces venideros” namespaces := Set new.

Page 47: Libro Smalltalk

Colecciones

Colecciones - Set

Ejemplos:

92S

ProgramandoconSmalltalk

93S Manos a la obra

Smalltalk cuenta con un framework de colecciones muy poderoso, hecho que no es

de extrañar, ya que lleva más de 20 años de depuración.

Contamos con numerosos tipos de colecciones (Bag, Set, OrderedCollection, Dic-

tionary, Array, etc) y, a su vez, con un rico y extenso protocolo de mensajes.

Algunos de los mensajes que se pueden enviar a todas las colecciones son los si-

guientes:

ß #add: agrega un objeto (dado como argumento) a la colección.

ß #addAll: agrega todos los elementos de la colección dada como argumento a la

colección receptora del mensaje.

ß #remove: remueve un determinado objeto de la colección y genera un error si el

elemento no es parte de la colección.

ß #remove: ifAbsent: remueve un determinado elemento de la colección y evalúa

el bloque dado si el elemento no es parte de la colección.

ß #removeAll: remueve todos los elementos del receptor que están contenidos en

la colección dada en el argumento.

ß #do: evalúa el bloque dado como argumento por cada elemento contenido en la

colección.Éste es el principal mensaje de las colecciones y, prácticamente, el resto

de mensajes están implementados usando el #do: de alguna forma. Es interesante

ver la implementación de, por ejemplo, los mensajes #select:, #collect:, #anyOne,

#detect:ifNone:, #do:separatedBy:, etc.

ß #do:separatedBy: evalúa el primer bloque dado como argumento por cada ele-

mento contenido en la colección y evalúa el segundo bloque entre elementos.

ß #select: evalúa el bloque dado por cada elemento del receptor como argumento

y colecciona los elementos en los que el bloque evalúa a true (verdadero) en una

colección del tipo del receptor. Responde esa colección nueva como resultado.

ß #reject: similar a #select:, pero colecciona los elementos para los que el bloque

evalúa a false.

ß #collect: evalúa el bloque dado por cada elemento del receptor como argumento

y colecciona los resultados en una colección del tipo del receptor. Responde esa

colección nueva como resultado.

ß #size responde el tamaño de la colección.

ß #anyOne responde algún elemento de la colección.

ß #atRandom responde uno de los elementos del receptor de forma aleatoria.

ß #detect: evalúa el bloque dado con cada elemento del receptor, devuelve el pri-

mer elemento donde el bloque evalúa a true y genera un error si ningún elemento

es encontrado.

ß #detect:ifNone: evalúa el bloque dado con cada elemento del receptor, devuelve

el primer elemento donde el bloque evalúa a true y evalúa el otro bloque dado si

ningún elemento es encontrado, devolviendo el resultado de esa evaluación.

ß #isEmpty responde si el receptor está vacío y no contiene elementos.

ß #includes: responde si el objeto dado es un elemento del receptor.

ß #includesAllOf: responde si todos los elementos de la colección dada están in-

cluidos en la colección receptora.

ß #includesAnyOf: responde si algunos de los elementos de la colección dada está

incluido en la colección receptora.

ß #allSatisfy: responde true si el bloque dado se evalúa a true por todos los ele-

mentos de la colección receptora.

ß #anySatisfy: responde true si el bloque dado se evalúa a true por algunos de los

elementos de la colección receptora.

ß #noneSatisfy: responde true si el bloque dado se evalúa a false por todos los

elementos de la colección receptora.

ß #occurrencesOf: responde cuantas veces está incluido el objeto dado en la colec-

ción receptora.

El Set es un tipo de colección que no mantiene ningún orden sobre sus elementos y,

además, no permite que un objeto esté contenido más de una vez. Por tanto, repre-

senta el concepto matemático de conjunto.

| set | set := Set new. set add: ‘un string’. set add: ‘otro string’. set add: ‘un string’. set add: ‘otro string’. set add: ‘un string’. set explore.

Page 48: Libro Smalltalk

94S

ProgramandoconSmalltalk

95S Manos a la obra

Al igual que el método anterior devuelve al receptor (si no se especifi ca una respuesta, el

método termina retornando self), el objeto SiteInfo será también responsable de respon-

der al mensaje #onNameSpace: (ver Figura 60).

Figura 60Figura 60

SonNamespace: aDictionary “Crea un nuevo namespace y lo guarda en la colección de namespaces del receptor” | namespace | namespace := Namespace new. namespaces add: namespace. ^ namespace

“convertir colecciones de diferente tipo a Set para remover los duplicados” #(5 4 1 2 2 2 1 2 1 2 3 4 3 2 3 4 5) asSet. ‘un string que tiene muchos caracteres’ asSet.

“Los 2 sets contienen sólo un elemento” (Set with: 1) = (Set with:1 with:1).

“El orden no importa” (Set with: 1 with: 2) = (Set with:2 with:1).

Valor de retorno por defecto

Los métodos que no tengan un valor de retorno explícito – usando el carácter ^ -

terminan devolviendo al receptor.

Colecciones – mensaje #add:

Agrega un objeto (dado por argumento) a la colección.

Ahora creamos el método en la clase SiteInfo (presionando sobre el botón Create), dentro

de la categoría parsing:

Figura 61Figura 61

S

De nuevo, el color rojo del sixtax-highlight nos avisa del desconocimiento de Namespace.

Para resolverlo creamos una nueva clase en la categoría de clases Squeakpedia y continua-

mos la ejecución presionando el botón Proceed. Seguidamente, el entorno nos avisa de un

nuevo error (ver Figura 61).

name: aByteString “Cambia el name del receptor” name := aByteString.

Vamos a resolverlo creando el método en la clase Namespace, dentro de la categoría de

métodos accessing, de la siguiente manera:

Una vez que aceptemos, se creará la variable de instancia name, y continuamos la ejecu-

ción con el botón Proceed (ver Figura 62).

Figura 62Figura 62

SBien, pues ya es el momento de procesar la creación de la primera página del Mediawiki.

Para ello, generamos el método en la clase Mediawiki, en la categoría parsing, siguiendo

los pasos que ya hemos dado varias veces, y lo implementamos así:

SS

los pasos que ya hemos dado varias veces, y lo implementamos así:

onPage: aDictionary “Crea una nueva página y la guarda en la colección de páginas del receptor” | page | page := Page new.

pages isNil ifTrue:[pages := Set new].

pages add: page.

^ page

Page 49: Libro Smalltalk

Figura 64

SFigura 65Figura 65

S

Figura 64

S

96S

ProgramandoconSmalltalk

97S Manos a la obra

Ahora hemos de crear la clase Page, dentro de la categoría de clases Squeakpedia, y la variable

de instancia pages al aceptar el método.

Debido a una inconsistencia en el formato XML de la Wikipedia, crearemos la colección de

páginas usando lazy-initialization, ya que los tags <page> no están contenidos en un tag <pa-

ges>, por lo que no podemos hacerlo siguiendo el mismo procedimiento que hemos usado

para la colección de namespaces de la clase SiteInfo.

Antes de continuar, vamos a inspeccionar el estado de nuestros objetos. Para ello, selecciona-

mos la opción self de los paneles que forman el Inspector del receptor y, desde el menú contex-

tual (botón azul), seleccionamos la opción explore ( | ) y tal y como nos muestra la Figura 63.

Figura 63Figura 63

S

Para validar si nuestro im-

portador está funcionando

correctamente, sólo hemos

de abrir y cerrar las distintas

ramas del árbol del Explo-

rador. Así, observamos que

hay tres namespaces en la

colección, que la variable de

instancia pages está en nil y

que otros datos del SiteInfo

refl ejan bien los datos del

XML (ver Figura 65). S97SS Manos a la obra

Explorador

El Explorador es una herramienta que cumple las mismas funciones que el Inspector,

pero con un formato de árbol que nos permite ir navegando a través de la estructu-

ra que forman nuestros objetos (ver Figura 64).

Las pequeños triángulos

azules que vemos en la

Figura 63 nos permiten

abrir o cerrar las ramas

para analizar la estructura

según nuestras preferen-

cias.

En el panel de código se

puede evaluar cualquier

sentencia de Smalltalk, la

única condición es que

la variable especial self

apuntará al objeto selec-

cionado en el panel superior y, si no hubiese ningún objeto seleccionado, apuntará

al objeto que está siendo explorado (la raíz del árbol).

Page 50: Libro Smalltalk

Figura 67Figura 67

SFigura 68Figura 68

S98S

ProgramandoconSmalltalk

99S Manos a la obra

Sin embargo, si comparamos los datos que tienen nuestros objetos con el XML de ejemplo,

vemos que los objetos Namespace de la estructura no contienen el dato key que viene

como atributo del tag.

Bien, por lo que vemos con el XML, es obvio que nos hemos olvidado de incluir el dato

key en el método donde hemos creado los objetos Namespace. Por tanto, ahora tenemos

que localizar el lugar en el que se instancian estos objetos, que encontraremos con facilidad

gracias a las herramientas que nos ofrece el entorno de Smalltalk. Para ello, seguimos el

proceso que describimos a continuación.

Empezamos buscando en el Explorador uno de los objetos Namespace y lo seleccionamos.

Después pedimos el menú contextual sobre ese objeto (con botón azul) y seleccionamos la

opción browse full (b) (o presionamos ALT-b), tal y como vemos en la Figura 66.

xml...

<namespaces>

<namespace key=”-1”>Specialis</namespace>

<namespace key=”0” />

<namespace key=”1”>Disputatio</namespace>

</namespaces>

...

Figura 66Figura 66

S

Esta secuencia nos abre el Browser de Clases indicando la clase del objeto seleccionado.

Pedimos el menú contextual sobre la clase SiteInfo y señalamos la opción class refs (N)

(o presionamos ALT-MAYÚSCULA-n), como nos muestra la Figura 67.

Esa opción nos abre un tipo de Browser que muestra los métodos donde se hace referencia

a la clase Namespace. Bien, seleccionamos la clase SiteInfo en el panel superior izquierdo y

después el método en el panel superior derecho, lo que nos mostrará el código del método

que instancia los Namespace (ver Figura 68).

Page 51: Libro Smalltalk

Figura 69Figura 69

S

Figura 70Figura 70

S

100S

ProgramandoconSmalltalk

101S Manos a la obra

¡Encontramos el error! El dato del atributo key del tag <namespace> está incluido en el

diccionario que recibimos por argumento, pero nosotros lo ignoramos. Por esto, ahora

vamos a corregir el método de la siguiente forma:

Ya estamos en disposición de cerrar algunas ventanas que no vamos a usar, como el Brow-

ser de Referencias, el Browser de Clases y el Explorador. Y, en el todavía abierto Depurador,

buscamos el contexto referente al método Mediawiki class>>fromFileNamed:, presio-

namos la opción Restart para reiniciar la ejecución y, acto seguido, pinchamos sobre el

botón Proceed.

onNamespace: aDictionary “Crea un nuevo namespace y lo guarda en la colección de namespaces del receptor” | namespace | namespace := Namespace key: (aDictionary at: ‘key’). namespaces add: namespace. ^ namespace

¿Qué ha ocurrido? Bien, vemos que se ha modifi cado la forma de instanciar los objetos

Namespace y nosotros no hemos actualizamos la clase. Por tanto, ahora vamos a selec-

cionar la opción Create y ordenamos que el método se cree dentro de la clase Namespace

class (ojo, ahora estamos creando un método de clase y no de instancia) y en la categoría

instance creation, tal y como nos muestra la Figura 70.

A continuación, implementamos el método de la siguiente manera:

key: aByteString “Devuelva una nueva instancia del receptor con el key dado” ^ self new initializeKey: aByteString

De nuevo, el sintax-highlight nos indica algo desconocido, en este caso, que no existe en

Smalltalk ningún método con el nombre #initializeKey: y que, probablemente, nos ha-

yamos equivocado de mensaje. No obstante, sabemos que no hemos cometido ninguna

equivocación, sólo que todavía no hemos creado el método correspondiente.

Seguidamente aceptamos el método y, ante la propuesta de alternativas de mensaje, selec-

cionamos la primera, que es la que realmente nos interesa, ya que nuestro mensaje no es

ningún error (ver Figura 71).

Figura 71Figura 71

S

Page 52: Libro Smalltalk

Figura 72Figura 72

SinitializeKey: aByteString “Inicializa el key del receptor” key := aByteString

Figura 73Figura 73

S

Figura 74Figura 74

Stitle: aByteString “Cambia el title del receptor” title := aByteString

id: aByteString “Cambia el id del receptor” id := aByteString

102S

ProgramandoconSmalltalk

103S Manos a la obra

Presionamos el botón Proceed para continuar y vemos el resultado en la Figura 72.

Ahora nos dice que un objeto de clase Namespace no entiende el mensaje #initializeKey:,

así que lo vamos a crear en esa misma clase, dentro de una nueva categoría de método

llamada initialization, y lo implementamos de la siguiente manera:

Nuevamente, el sintax-highlight nos indica que no conoce nada con el nombre key, así que

aceptamos y creamos una variable de instancia, tal y como vemos en la Figura 73.

102SS

Seguimos con la ejecución presionando el botón Proceed, como siempre hacemos (ver

Figura 74).

A continuación, generamos la variable de instancia title al aceptar y hacemos lo mismo

para el método #id: creando, también, la variable de instancia cuando aceptamos:

Llegados a este punto, vamos a detenernos unos instantes para implementar el método

#onRevision: (ver Figura 75).

Creamos el método en la clase Page dentro de la categoría accessing:

Figura 75Figura 75

S

Page 53: Libro Smalltalk

id: aByteString “Cambia el id del receptor” id := aByteString

timestamp: aByteString “Cambia el timestamp del receptor” timestamp := aByteString

104S

ProgramandoconSmalltalk

105S Manos a la obra

Así, procedemos a crearlo dentro de la clase Page, en una nueva categoría llamada

parsing:

Al aceptar este método, creamos la variable de instancia revision y la clase Revision dentro

de la categoría de clases Squeakpedia. Después, continuamos la ejecución con el botón

Proceed (ver Figura 76).

onRevision: aDictionary “Crea una nueva revision guardándola en la coleccion de revisiones del receptor”

| revision |

revisions isNil ifTrue:[revisions := OrderedCollection new].

revision := Revision new.

revisions add: revision.

^ revision

Figura 76Figura 76

STipos de Colecciones OrderedCollection

Las colecciones OrderedCollection mantienen el mismo orden en el que han sido insertados sus elementos.

Al ser una colección con sentido de orden, expone un protocolo que incluye mensa-jes para acceder a los elementos por su posición, por ejemplo: #fi rst, #second, #third, #last, #allButFirst, #allButLast, #addLast:, #addFirst:, #add:after:, #addBefore:, etc.

Ahora hemos de completar la implementación de la clase Revision creando, primero, el

método #id: dentro de la categoría accessing con su correspondiente variable de instancia:

Figura 77Figura 77

SDespués implementamos el método #timestamp: en la clase Revision, dentro de la catego-

ría accessing y creamos, al aceptar el método, la variable de instancia:

Continuamos implementando el método #onContributor: en la categoría parsing, creán-

dose la variable de instancia contributor y la clase Contributor dentro de la categoría

Squeakpedia.

Figura 78Figura 78

S

Page 54: Libro Smalltalk

106S

ProgramandoconSmalltalk

107S Manos a la obra

Tras este paso nos toca implementar el método #ip: en la clase Contributor, dando lugar,

así, a la variable de instancia correspondiente:

Aceptamos e inmediatamente después se creará la variable de instancia correspondiente.

Debido a que el mayor porcentaje de los datos corresponde a textos, los vamos a guardar

comprimidos para que ocupen menos espacio. Ésta es la razón por la que enviamos el

mensaje #zipped al String después de asegurarnos que el argumento sea un ByteString.

Continuamos con el ejemplo (ver Figura 80):

onContributor: aDictionary “crea un contributor y lo guarda en el receptor” contributor := Contributor new. ^ contributor

ip: aByteString “Cambia el ip del receptor” ip := aByteString

Figura 79Figura 79

Stext: aByteString “Cambiar el text del receptor” text := aByteString asByteString zipped

Y llegamos al, posiblemente, método más importante del importador. Creamos el méto-

do en la clase Revision (ver Figura 79), dentro de la categoría accessing, de la siguiente

forma:

Creamos el método #comment: en la clase Revision y dentro de la categoría accessing:

Y, fi nalmente, se generará la variable de instancia al aceptar.

Bien, pues ya hemos terminado el proceso, pero vamos a comprobar el resultado para va-

lidar que los datos del XML de ejemplo se muestren en nuestros objetos. Así, comenzamos

la exploración tal y como nos muestra la Figura 81.

Y navegamos a través de los objetos generados (ver Figura 82).

Figura 80Figura 80

Scomment: aByteString “Cambia el comment del receptor” comment := aByteString

Figura 81Figura 81

S

Page 55: Libro Smalltalk

108S

ProgramandoconSmalltalk

109S Manos a la obra

A simple vista, parece que todo está correcto, sólo que la validación del texto que hemos

comprimido anteriormente requiere más atención. Para ello, vamos a implementar un

método que descomprima el texto.

Figura 82

A simple vista, parece que todo está correcto, sólo que la validación del texto que hemos

Figura 82

SFigura 83Figura 83

S

Primero, seleccionamos en el Explorador algún objeto de clase Revision y tecleamos en el

panel inferior lo que nos muestra la Figura 83.

text “Responde el text del receptor” ^ text unzipped

Figura 85Figura 85

S

Figura 84Figura 84

SPara continuar, sólo tenemos que presionar sobre el botón Proceed, como venimos ha-

ciendo hasta ahora. El resultado lo vemos en la Figura 85 y aparentemente el texto

está bien.

Después lo evaluamos con print it print it (p) (o ALT-p).

Y, seguidamente, lo implementamos en la categoría accessing de la siguiente forma:

Page 56: Libro Smalltalk

xml

...

<page>

<title>Arithmetica</title>

<id>5</id>

<revision>

<id>45467</id>

<timestamp>2005-10-21T01:42:12Z</timestamp>

<contributor>

<username>FlaBot</username>

<id>509</id>

</contributor>

<minor />

<comment>Bot: Fixing wiki syntax</comment>

<text xml:space=”preserve”>== De vocabulo Arithmeticae disciplinae ==...</text>

</revision>

</page>

...

parser onTextTag: ‘username’ send: #username:.

110S

ProgramandoconSmalltalk

111S Manos a la obra

Ahora vamos a validar el importador procesando algún archivo real y de mayor tamaño,

por ejemplo, comencemos importando la Wikipedia en Latín. Es posible que, al procesar

un archivo mayor, encontremos que falta la implementación de algún otro tag que no

teníamos en el ejemplo anterior.

Así, tecleamos las líneas que vemos en la Figura 86, dentro del Workspace, y selecciona-

mos la correspondiente al archivo de la Wikipedia en Latín y lo ejecutamos explorando el

resultado.

Y obtenemos lo que nos muestra la Figura 87.

Bien, parece que tendremos que implementar algunos métodos más para procesar este

ejemplo. No obstante, esto no debe suponernos un problema porque a estas alturas ya

debemos manejar perfectamente el Depurador.

A lo largo del presente capítulo ya hemos trabajado sobre un error como éste, pero lo que

está ocurriendo ahora es que el parser nos indica que desconoce cómo reaccionar ante el

tag <username>.

Así pues, vamos a buscar en el XML el lugar donde se encuentra el tag y vemos que es otro

dato que pueden tener los Contributor. Seguidamente, instruimos al parser, en el método

Mediawiki class>>fromFileNamed: sobre un nuevo text-tag de la siguiente forma:

Ahora, reiniciamos la ejecución (ver Figura 88).

Figura 86Figura 86

SFigura 87Figura 87

S Figura 88Figura 88

S

Page 57: Libro Smalltalk

112S

ProgramandoconSmalltalk

113S Manos a la obra

Y, a continuación, debemos implementar el método #username: como ya sabemos (clase

Contributor dentro de la categoría de métodos accessing, variable de instancia, etc.)

Seguimos tal y como nos indica la Figura 89,

y ejecutamos el mismo procedimiento para el método #id:

Ahora observamos el mensaje que nos muestra la Figura 90,

Seguimos tal y como nos indica la Figura 89

username: aByteString “Cambia el username del receptor” username := aByteString

Figura 89

y ejecutamos el mismo procedimiento para el método #id:

Figura 89

SAhora observamos el mensaje que nos muestra la Figura 90

id: aByteString “Cambia el id del receptor” id := aByteString

Figura 90Figura 90

S...

<page>

<title>Arithmetica</title>

<id>5</id>

<revision>

y vemos que ha aparecido otro tag que desconoce el parser.

Algunas revisiones tienen una especie de marca que indica que son revisiones-menores.

Seguidamente, vamos a instruir al parser con esta orden:

Y reiniciamos el proceso de nuevo (ver Figura 91).

Ahora implementamos el método #onMinor: dentro de la categoría parsing, de la siguien-

te manera:

y creamos la variable de instancia al aceptar.

Debido a la forma en que el XML nos avisa cuando alguna revisión es menor (el tag apa-

rece solo para las revisiones menores y no hay nada que indique lo contrario), deberíamos

xml

<id>45467</id>

<timestamp>2005-10-21T01:42:12Z</timestamp>

<contributor>

<username>FlaBot</username>

<id>509</id>

</contributor>

<minor />

<comment>Bot: Fixing wiki syntax</comment>

<text xml:space=”preserve”>== De vocabulo Arithmeticae disciplinae ==</text>

</revision>

</page>

...

parser onTag: ‘minor’ send: #onMinor:.

onMinor: aDictionary “Marca al receptor como minor” minor := true.

Figura 91

Ahora implementamos el método #onMinor: dentro de la categoría parsing, de la siguien-

Figura 91

S

Page 58: Libro Smalltalk

114S

ProgramandoconSmalltalk

115S Manos a la obra

preguntarnos qué pasaría con la variable minor en las revisiones no-menores. Bien, tal y

como tenemos el código en este punto, disponemos de un true para las revisiones menores

y un nil para las demás. Para verifi carlo, podemos inicializar la variable en false.

Para ejecutar esta acción podemos utilizar el Browser de Clases y dejamos el Depurador

por unos momentos. Así, abrimos el menú del Mundo | open... | browser (b) o ALT-b,

seleccionamos la categoría de clases Squeakpedia, después, la clase Revision, y en el panel

correspondiente a las Categorías de Métodos invocamos el menú contextual (botón azul) y

escogemos la opción new category... como vemos en la Figura 92.

Figura 92Figura 92

SA continuación, elegimos la opción new.. (ver Figura 93):

Y tecleamos initialization, como vemos en

la Figura 94.

Figura 93

Y tecleamos

la

Figura 93

S Figura 94Figura 94

S

Al aceptar, el Browser nos muestra una plantilla de método en el panel inferior, tal y como

aparece en la Figura 95:

reemplazamos esta plantilla con la siguiente instrucción:

y aceptamos.

Figura 95Figura 95

Sinitialize “Inicializa el receptor” minor := false.

Inicialización de objetos

En las versiones más actuales de Squeak las instancias reciben el mensaje #initialize inmediatamente después de ser creadas, pero en otros dialectos de Smalltalk esto no es posible.

En el caso que usemos otro dialecto o una versión antigua de Squeak, se debería enviar el mensaje #initialize desde el método de clase #new de forma similar a lo que hicimos con el mensaje de clase #key: y el método de instancia #initializeKey: de la clase Namespace.

Page 59: Libro Smalltalk

xml

116S

ProgramandoconSmalltalk

117S Manos a la obra

Bien, pues ya podemos reiniciar la ejecución. Ahora el proceso durará bastante más, pero

no hemos de preocuparnos porque eso indica que está procesando el XML sin problemas,

y nos muestra lo que vemos en la Figura 96.

Seguidamente, buscamos el tag en el XML y observamos que algunas páginas tienen res-

tricciones.

A continuación, ordenamos al parser que procese los tags <restrictions> como un text-tag

enviando el mensaje #restrictions: y reiniciamos el proceso (ver Figura 97):

...

<page> <title>Pagina prima</title> <id>328</id> <restrictions>sysop</restrictions> <revision> <id>46417</id> <timestamp>2005-10-29T06:52:57Z</timestamp> <contributor> <username>MycÄ“s</username> <id>79</id> </contributor> <comment>svg</comment> <text xml:space=”preserve”>&lt;!-- Please note that most </text> </revision> </page>...

Figura 97Figura 97

SDespués, creamos el método y la variable de instancia y seguimos. Al cabo de, aproximada-

mente 1 minuto y 40 segundos (en la máquina del autor), el proceso termina satisfactoria-

MessageTally spyOn:[Mediawiki fromFileNamed: ‘Wikipedia_Latina_pages_current_20051113.xml’]

mente. Pero, antes de abandonar el ejemplo vamos a averiguar dónde se está consumiendo

el tiempo, y para ello hemos de utilizar la clase MessageTally de la siguiente manera:

Figura 98Figura 98

SS

y obtenemos el resultado que nos muestra la Figura 98:

MessageTally

La herramienta MessageTally recolecta información sobre la cantidad de tiempo que

se consume en los métodos, mostrándonoslo de forma clara para poder optimizar

nuestro código en cuanto a velocidad de ejecución.

Figura 96

Seguidamente, buscamos el tag en el XML y observamos que algunas páginas tienen res-

Figura 96

S

Page 60: Libro Smalltalk

118S

ProgramandoconSmalltalk

119S Manos a la obra

Si prestamos atención a los resultados del MessageTally, la Figura 99 nos muestra que el

63.3% del tiempo se está consumiendo al comprimir los textos.

Como es lógico, no tiene ningún sentido comprimir textos de pequeño tamaño, por lo que

vamos a modifi car ligeramente el método #text: para comprimir sólo los textos de más de

2 Kbytes.

En este caso no es necesario que modifi quemos el método #text porque #unzziped es lo

sufi cientemente inteligente como para darse cuenta que el string no está comprimido.

Así pues, volvemos a ejecutar el importador, usando el MessageTally, para ver el impacto de

nuestro cambio (ver Figura 100).

Comprobamos que hemos reducido el tiempo de 115 segundos a 63 segundos, un ahorro

importante para un cambio de 3 o 4 líneas de código.

Otra opción para conseguir esta optimización hubiese sido usar el TimeProfi leBrowser,

pero para ello hay que evaluar lo siguiente (ver Figura 101):

Figura 99

Como es lógico, no tiene ningún sentido comprimir textos de pequeño tamaño, por lo que

Figura 99

S2 Kbytes.

text: aByteString “Cambiar el text del receptor”

| string |

string := aByteString asByteString.

text := (string size > 2048) ifTrue:[string zipped] ifFalse:[string].

TimeProfi leBrowser spyOn:[Mediawiki fromFileNamed: ‘Wikipedia_Latina_pages_current_20051113.xml’].

Figura 100Figura 100

S

TimeProfi lerBrowser

El TimeProfi leBrowser muestra los mismos datos que el MessageTally, pero los pre-

senta en un Browser que permite modifi car directamente los métodos.

Figura 101Figura 101

SS

S

Page 61: Libro Smalltalk

120S

ProgramandoconSmalltalk

121S Manos a la obra

Con esto damos por concluido el ejemplo del importador de Wikipedia. Así, sólo hemos

llevado los datos al Squeak pero sin hacer nada con ellos, no obstante, el objetivo del libro

es enseñar a utilizar el entorno de Smalltalk y no crear una aplicación.

De cualquier forma, los lectores quedan invitados a completar esta aplicación dotándola

de nuevas funcionalidades.

3.4 Motor de Workfl ow

El desarrollo del ejemplo anterior se ha basado en el parseo de un archivo. Smalltalk nos

ofrece excelentes alternativas para interactuar con información externa a la imagen (archi-

vos, bases de datos tanto relacionales como de objetos, sockets de tcp, etc).

Sin embargo, cuando creamos un sistema que sí está contenido completamente en la ima-

gen, las ventajas se multiplican. Prueba de ello es que, al manipular objetos de nuestra

imagen, nos olvidamos de, por ejemplo, abrir y cerrar conexiones, abrir y cerrar archivos,

de situaciones de errores por modifi cación de la información por otros programas, etc. y

sólo aplicamos las reglas de un entorno de objetos: objetos y mensajes.

Vamos a ver el último ejemplo de este capítulo para poner en práctica los conocimientos

que ya hemos adquirido. En este caso, desarrollaremos, también paso a paso, un pequeño

motor de Workfl ow.

Workfl ow

El fl ujo de trabajo (Workfl ow, en inglés) es el estudio de los aspectos operacionales

de una actividad: cómo se estructuran las tareas, cómo se realizan, cuál es su orden

correlativo, cómo se sincronizan, cómo fl uye la información que soporta las tareas

y cómo se lleva a cabo el seguimiento para el cumplimiento de las tareas. General-

mente, los problemas de fl ujo de trabajo se resuelven con redes de Petri.

Si bien el concepto de fl ujo de trabajo no es específi co a la tecnología de la infor-

mación, una parte esencial del software para trabajo colaborativo (groupware) es

justamente el fl ujo de trabajo.

3.4 En nuestro ejemplo vamos a utilizar una metodología muy similar al Test Driven

Development.

Podemos obtener más información en:

ß http://es.wikipedia.org/wiki/Workfl ow

ß http://en.wikipedia.org/wiki/Workfl ow

Test Driven Development

El objetivo de todo programador debería ser el de generar Código Limpio que Fun-

ciona (CLQF). Existen numerosas razones para escribir este tipo de código, entre

ellas, cabe destacar:

ß Generar CLQF es una forma predecible de desarrollar. Se puede saber cuándo

termina el desarrollo y despreocuparnos por un largo ciclo de depuración.

ß El CLQF nos ofrece la posibilidad de aprender todo lo que el código tiene que

decirnos.

ß El CLQF brinda mejores ventajas a los usuarios de nuestro software.

ß El CLQF permite que confi emos en nuestros compañeros y que ellos confíen en

nosotros.

ß Cuando escribimos CLQF nos sentimos mejor con nosotros mismos.

Sin embrago, existen muchos obstáculos para escribir CLQF, entonces ¿cómo po-

demos generarlo? Bien, la metodología Test Driven Development (TDD) consiste

en que los tests automáticos sean los que rijan el desarrollo. Para ello, seguimos la

siguientes reglas:

1. Escribir nuevo código sólo si tenemos un test automático que falla.

2. Eliminar la duplicación.

La aplicación de estas dos reglas imprime el siguiente ritmo al proceso de desarrollo:

ß Rojo: escribir un test que falle.

ß Verde: hacer que el test funcione lo más rápidamente posible. Podemos cometer

Page 62: Libro Smalltalk

122S

ProgramandoconSmalltalk

123S Manos a la obra

Puesto que toda la funcionalidad se implementa sólo después de que un determinado test

lo requiera, un sistema desarrollado de esta forma contiene decenas, incluso centenares de

tests. La administración de los test es, pues, parte del desarrollo, por lo que es conveniente

contar con herramientas que nos ayuden. Para escribir y administrar los tests usaremos el

framework llamado SUnit.

cuantos errores queramos en esta etapa, ya que el objetivo es salirse del rojo cuanto

antes.

ß Refactorizar: eliminar toda la duplicación creada en el paso anterior.

Podemos encontrar más información en el libro: “Test-Driven Development by Exam-

ple” (ver bibliografía) y en http://es.wikipedia.org/wiki/Tdd y http://en.wikipedia.

org/wiki/Test_driven_development

SUnit

SUnit es el origen de todos los frameworks de Unit Testing.

Para más información, podemos consultar:

ß http://sunit.sourceforge.net/

ß http://www.xprogramming.com/testfram.htm

ß http://es.wikipedia.org/wiki/Prueba_unitaria

ß http://en.wikipedia.org/wiki/Unit_test

ß http://www.iam.unibe.ch/~ducasse/Programmez/OnTheWeb/Art8-SUnit.pdf

ß http://www.iam.unibe.ch/~ducasse/Programmez/OnTheWeb/SUnitEnglish2.pdf

Para ayudarnos en la tarea de refactorización nos serviremos de otra herramienta: el

Refactoring Browser.

Refactoring Browser y Refactoring

El Refactoring Browser es una variante del Browser de Clases que nos ofrece opciones

para automatizar las operaciones típicas de refactoring.

Y una vez que aclarados algunos conceptos comencemos con el ejemplo. Nuestro humilde

motor de Workfl ow estará compuesto, principalmente, por dos grandes grupos de objetos:

la defi nición de los procesos y las instancias de los procesos.

Las defi niciones son la explicación de cómo han de ser los procesos. Imaginemos que, por

ejemplo, los procesos llamados Venta comienzan después de recibir una orden de pedido.

Bien, entonces tendríamos que emitir una orden de producción para que la fábrica se pon-

ga en funcionamiento, después, informaríamos al departamento contable sobre la nueva

deuda que el cliente tendrá con nuestra empresa, etc.

Las defi niciones, por tanto, enumeran una serie de estados y los movimientos entre ellos.

Para más información podemos consultar: http://st-www.cs.uiuc.edu/users/brant/

Refactory/

Se llama Refactoring al proceso de modifi car el código de un desarrollo para

mejorar su estructura interna sin alterar la funcionalidad que ofrece externamente,

lo que se conoce informalmente por limpiar el código. Los tests aseguran que la

refactorización no cambia el comportamiento del código.

Podemos encontrar más información en el libro: “Refactoring – Improving the design

of existing code” (ver bibliografía).

Figura 102Figura 102

SSLas instancias de procesos son las representaciones, en nuestro sistema, de una operación

en curso. Siguiendo el ejemplo anterior, podemos decir que una instancia de la defi nición

Venta es cuando el cliente Juan Pérez nos pide 100 escritorios. Otra instancia, de la misma

defi nición, es cuando otro cliente nos pide otro producto. Varias instancias corresponden,

por tanto, a una única defi nición, ya que ésta sólo indica cómo es el procedimiento y las

instancias son una venta en particular.

Para empezar a escribir un poco de código (el autor ya lo está deseando después de tanta

introducción), comencemos con un test que pruebe la defi nición más simple que se nos

Page 63: Libro Smalltalk

Pensar primero en la interfaz pública

Cuando escribimos un test es conveniente que evitemos pensar en cómo vamos

a implementar las clases y sus métodos. Sólo nos concentramos en cómo nos

gustaría usar esos objetos.

Si pensamos en cómo se usan los objetos (su interfaz pública) antes de cómo se

resolverán los mensajes (los métodos), crearemos interfaces mucho más limpios.

124S

ProgramandoconSmalltalk

125S Manos a la obra

ocurra y obtengamos el color rojo. Bien, usamos el Browser de Clases para crear, primero,

una categoría de clases llamada Workfl ow y luego creamos una subclase de TestCase llama-

da Workfl owTest, tal y como vemos en la Figura 103.

A continuación, creamos una categoría de métodos llamada running y, dentro, generamos

un método llamado #testLaMasSimpleDefi nición.

Figura 103

ón, creamos una categoría de métodos llamada y, dentro, generamos

Figura 103

SLos métodos de testing comienzan por #test

Los métodos que comienzan con #test serán considerados métodos de testing por

el framework SUnit. De este modo, cuando le ordenemos al framework que ejecute

todos los test de una determinada clase, éste invocará a todos los métodos cuyos

nombres comiencen con #test. El resto del nombre, por convención, nos describe

qué es lo está probando el método.

La defi nición más simple que se le ocurre a nuestro autor, es algo que comience y termine

inmediatamente, algo como lo que nos muestra la Figura 104:

Figura 104Figura 104

SS

Ahora traducimos ese gráfi co a código Smalltalk. Así, decidimos que vamos a defi nir las

transiciones y éstas harán referencia a los estados:

testLaMasSimpleDefi nición “Prueba la defi nición más simple posible” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar y terminar’ desde: ‘principio’ hasta: ‘fi n’.

self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 1]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 2]

Estructura de los test

Prácticamente todos los test tienen la siguiente estructura:

ß Instanciación de los objetos.

ß Alguna operación sobre los objetos.

ß Especifi cación del resultado esperado.

Para especifi car cuál es el resultado esperado disponemos de varios métodos

(heredados de TestCase), de los que los más importantes son:

Page 64: Libro Smalltalk

Figura 108Figura 108

S126S

ProgramandoconSmalltalk

127S Manos a la obra

Al aceptar el método, el ambiente nos informa que desconoce Defi niciónDeProces. Para

solucionarlo, elegimos crear una clase, herencia de Object, en la categoría Workfl ow. A

continuación, nos dice que #agregarDefi niciónDeTransición:desde:hasta: es un selector

también desconocido, pero nosotros confi rmamos que está bien escrito. Después hacemos

lo mismo con los selectores #defi nicionesDeTransiciones y #defi nicionesDeEstado, por

lo que el Browser nos queda tal y como muestra la Figura 105:

ß #assert: especifi ca que el argumento debe ser true.

ß #deny: especifi ca que el argumento debe ser false.

ß #should: especifi ca que el argumento (normalmente un bloque) debe evaluarse

a true.

ß #shouldnt: especifi ca que el argumento (normalmente un bloque) debe evaluarse

a false.

ß #should:raise: especifi ca que la evaluación del primer argumento (normalmente

un bloque) debe lanzar una excepción de la clase dada (normalmente alguna

subclase de Exception) en el segundo argumento.

ß #shouldnt:raise: especifi ca que la evaluación del primer argumento (normalmente

un bloque) no debería lanzar una excepción de la clase dada (normalmente alguna

subclase de Exception) en el segundo argumento.

Figura 105Figura 105

S

Ahora abrimos la herramienta llamada SUnit Test Runner a través del menú del Mundo |

open... | SUnit Test Runner (ver Figuras 106 y 107), que es la encargada de ejecutar nues-

tros test.

Figuras 106 - 107Figuras 106 - 107

SSUnit Test Runner

Esta herramienta nos per-

mite ejecutar automática-

mente todos los tests de las

clases seleccionadas, mos-

trándonos todas las clases

que son herencias de Test-

Case pudiendo seleccionar

las que queramos.

Los botones tienen las

siguientes funciones: S

Page 65: Libro Smalltalk

128S

ProgramandoconSmalltalk

129S Manos a la obra

Figura 109Figura 109

SSFigura 110Figura 110

S

Al abrirse el SUnit Test Runner, vemos que tiene seleccionadas todas las clases, por lo que

presionamos el botón deselect all para quitar esa selección y, a continuación, presionamos

sobre el botón Filter e ingresamos, en el cuadro de diálogo: Workfl ow* (ver Figura 109).

ß Refresh: vuelve a actualizar la lista de clases. Resulta útil cuando creamos nuevas

clases de test o borramos alguna ya existente.

ß Filter: nos permite seleccionar clases usando caracteres comodines.

ß Stop: detiene la ejecución de los tests.

ß Run One: ejecuta los tests de la clase seleccionada.

ß Run All: ejecuta los tests de todas las clases seleccionadas.

ß select all: selecciona todas las clases de test.

ß deselect all: quita la selección todas las clases de test.

ß togle selections: invierte la selección. Las clases seleccionadas dejan de estarlo y

viceversa.

Los dos paneles inferiores muestran la lista de tests que han fallado. Pueden darse

dos tipos de fallos en los tests:

1. La condición que exigimos en el test no se cumple. A estos tests se los asocia el

color amarillo y se muestran en el panel central.

2. El test cancela y no termina de ejecutar. A estos test se los asocia con el color rojo

y se muestran en el panel inferior.

Haciendo clic sobre el test con el fallo se abrirá el pre-Depurador mostrando el error

correspondiente, pudiéndose utilizar el Depurador para corregir el fallo.

Al aceptar, nuestra clase de test

recién creada queda selecciona-

da, tal y como nos muestra la

Figura 110: S

Figura 111Figura 111

S

Llegados a este punto, ya estamos listos para ejecutar, por primera vez, nuestro test

presionando el botón Run One (ver Figura 111).

¡Eureka! Ya tenemos el rojo que estábamos buscando.

Según el TDD, en este momento debemos escaparnos del rojo lo más rápidamente posi-

ble. Incluso estamos autorizamos a cometer cuantas infracciones necesitemos con tal de

lograrlo cuanto antes. Bien, ahora hacemos clic sobre el test en rojo (en el panel inferior),

tal y como vemos en la Figura 112:

Figura 111Figura 111

Sy obtenemos el pre-Depurador (ver Figura 113):

Page 66: Libro Smalltalk

130S

ProgramandoconSmalltalk

131S Manos a la obra

Figura 114Figura 114

S

Figura 113Figura 113

SLlegamos ante una situación conocida: un objeto no entiende un determinado mensaje

y el pre-Depurador nos ofrece crear el método. Así pues, lo ejecutamos en la clase

Defi niciónDeProceso, dentro de la categoría accessing.

Al aceptar, el entorno nos ofrece la posibilidad de crear la variable de instancia transiciones,

nosotros aceptamos la propuesta y el Depurador nos queda como muestra la Figura 114:

SagregarDefi niciónDeTransición: transiciónString desde: estadoDesdeString hasta: estadoHastaString

“Agrega una defi nición de transición con el nombre dado, que une dos estados de nombres dados”

transiciones add: {transiciónString. estadoDesdeString. EstadoHastaString}

S

Continuamos, presionando el botón Proceed, y obtenemos lo que nos muestra la Figura 115:

Ahora, pinchando sobre el botón Debug, paramos unos instantes para analizar qué es

lo que está pasando. Así, seleccionamos, en el panel superior, el método Defi niciónDe-

Proceso>>agregarDefi niciónDeTransición:desde:hasta:. Tras esta operación, compro-

bamos que el mensaje se está enviando a la recién creada variable de instancia transi-

ciones. Así pues, seleccionamos la variable de instancia en el panel inferior izquierdo y

observamos que, en el panel siguiente, aparece un nil (ver Figura 116).

Figura 115

Ahora, pinchando sobre el botón Debug, paramos unos instantes para analizar qu

Figura 115

SFigura 116Figura 116

S

Page 67: Libro Smalltalk

132S

ProgramandoconSmalltalk

133S Manos a la obra

En la variable que acabamos de ver deberíamos tener algún tipo de colección como, por

ejemplo, un Set. Bien, nos encontramos de nuevo ante un caso ya conocido: podemos

implementar el método #initialize para inicializar la variable de instancia transiciones o

podemos usar el idiom lazy-initialization. Preferimos, en este punto, la opción del lazy-ini-

tialization ya que nuestro objetivo es escapar del rojo con la máxima rapidez. La podemos

implementar directamente en el Depurador con las siguientes órdenes:

agregarDefi niciónDeTransición: transiciónString desde: estadoDesdeString hasta: estadoHastaString

“Agrega una defi nición de transición con el nombre dado, que une dos estados de nombres dados”

transiciones isNil ifTrue:[transiciones := Set new].

transiciones add: {transiciónString. estadoDesdeString. EstadoHastaString}

Aceptamos y continuamos presionando el botón Proceed (ver Figura 117):

Figura 117Figura 117

SSdefi nicionesDeTransiciones “Responde las defi niciones de transiciones del receptor” ^ transiciones

Ahora implementamos el método en la clase Defi niciónDeProceso, dentro de la categoría

accessing, de la siguiente forma:

Seguidamente, aceptamos y continuamos (ver Figura 118).

Figura 118Figura 118

S

De nuevo, implementamos el método en la clase Defi niciónDeProceso, en la categoría

accessing, con las siguientes instrucciones:accessing, con las siguientes instrucciones:

defi nicionesDeEstados “Responde las defi niciones de estados del receptor”

| resultado |

resultado := Set new. resultado addAll: (transiciones collect: [:each | each second]). resultado addAll: (transiciones collect: [:each | each third]).

^ resultado.

Colecciones - mensaje #collect:

Evalúa el bloque dado por cada elemento del receptor como argumento, reúne los

resultados en una colección del tipo del receptor y responde esa colección nueva

como resultado.

Ejemplos: “la tabla del 2” (1 to: 10) collect: [:each | each * 2].

“¿par o impar?” (1 to: 10) collect: [:each | each even].

“todo a mayúsculas” ‘una cadena’ collect: [:each | each asUppercase].

Nuevamente, aceptamos y continuamos, como venimos haciendo en todo el ejemplo.

Ahora la operación termina bien, por lo que podemos volver a ejecutar para obtener el

verde presionando el botón Run One, como nos muestra la Figura 119.

Figura 119Figura 119

S

Page 68: Libro Smalltalk

134S

ProgramandoconSmalltalk

135S Manos a la obra

Según el TDD, debemos refactorizar el código para deshacernos de todas las infracciones

que hayamos cometido en el paso anterior. El método que implementamos no ha

quedado muy claro, así que procedemos a limpiarlo. Para ello, buscamos el método

Defi niciónDeProceso>>defi nicionesDeEstados en el Browser de Clases, tal y como

vemos en la Figura 120:

Figura 120Figura 120

SBien, lo primero que vamos a hacer es mejorar la legibilidad del método usando el patrón

llamado Explaining Temporary Variable.

Resulta barato escribir código limpio

El código se lee y se modifi ca muchísimas veces más de las que se escribe. Por

ello, cualquier inversión que hagamos en generar código limpio y entendible

reportará muchos benefi cios en el futuro.

Explaining Temporary Variable (Variable Temporal Explicativa)

¿Cómo se puede simplifi car una expresión compleja dentro de un método?

Figura 121Figura 121

SSFigura 122SFigura 122

S

Para llevar a cabo esta refactorización utilizaremos una de la funcionalidades del Refacto-

ring Browser. Así, procedemos a seleccionar la sub-expresión que queremos extraer, tal y

como vemos en la Figura 121.

Esta tarea se consigue extrayendo una sub-expresión desde la expresión compleja,

asignando el valor a una variable temporal antes de la expresión compleja y

reemplazando la sub-expresión por la variable. El nombre de la variable indicará

qué signifi ca la expresión extraída, aumentando la legibilidad del método.

Más información en el libro: “Smalltalk Best Practice Patterns” (ver bibliografía).

Después, pedimos el menú

contextual y elegimos la opción

extract to temporary..., que se

encuentra dentro del sub-menú

selection... (ver Figura 122).

S

Page 69: Libro Smalltalk

136S

ProgramandoconSmalltalk

137S Manos a la obra

En el cuadro de diálogo que nos aparece tecleamos el nombre de la variable temporal:

estadosDesde (ver Figura 123).

Figura 123Figura 123

SS Tras aceptar, podemos ver el resultado de esta

operación en la Figura 124:

Figura 124Figura 124

SFigura 125Figura 125

SSDe nuevo, repetimos el proceso

para la otra sub-expresión (ver

Figura 125),

Ahora reescribimos el método de la siguiente forma:

usando estadosHasta como nombre de variable temporal (ver Figura 126).

Figura 126

Ahora reescribimos el método de la siguiente forma:

Figura 126

Sdefi nicionesDeEstados “Responde las defi niciones de estados del receptor”

| estadosDesde estadosHasta | estadosDesde := transiciones collect: [:each | each second]. estadosHasta := transiciones collect: [:each | each third]. ^ (estadosDesde , estadosHasta) asSet.

Colecciones – mensaje #

Concatena el receptor y el argumento en una sola colección y responde la nueva

colección.

Ejemplos: ‘un string’ , ‘ ‘ , ‘otro string’.

#(1 2) , #( 3 4).

#(1 2) , ‘diego’.

(1 to: 10) , (1 to: 5).

Page 70: Libro Smalltalk

138S

ProgramandoconSmalltalk

139S Manos a la obra

Figura 128Figura 128

S

El método, escrito de esta manera, deja muy claro que todas las defi niciones de estados son

la concatenación de los Estadosdesde y los Estadoshasta, sin duplicados.

Ahora es el momento de ejecutar nuevamente los tests automáticos para asegurarnos que

no hemos roto nada con la refactorización (ver Figura 127).

Figura 127Figura 127

SSYa hemos cumplido uno de los ciclos del TDD. A continuación, vamos a escribir un test

antes de implementar la funcionalidad, obtendremos un rojo, por lo que pasamos al verde

lo más rápido posible, y refactorizamos el código para que quede CLQF (Código Limpio

Que Funciona).

De nuevo, escribimos otro test que instancie una defi nición de proceso un poco más

complicada (ver Figura 128):

SSeguidamente introducimos otro test, en la misma clase:

y ejecutamos los tests tal y como vemos en la Figura 129:

testDefi niciónSimple “Prueba una defi nición simple” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘A’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘A’ hasta: ‘fi n’.

self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 2]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 3].

Figura 129Figura 129

SVemos que no está nada mal. La implementación que hemos realizado es sufi ciente para

el caso anterior, pero ahora vamos a introducir un caso aún más complicado que el que

acabamos de ver (ver Figura 130).

Page 71: Libro Smalltalk

140S

ProgramandoconSmalltalk

141S Manos a la obra

Introducimos otro test con el siguiente código:

Figura 130

Introducimos otro test con el siguiente código:

Figura 130

SStestDefi niciónNoTrivial “Prueba una defi nición no trivial” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘principio’ hasta: ‘A’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘A’ hasta: ‘B’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘anterior’ desde: ‘B’ hasta: ‘A’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘B’ hasta: ‘C’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘anterior’ desde: ‘C’ hasta: ‘B’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘C’ hasta: ‘fi n’.

self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 6]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 5].

y ejecutamos de nuevo los tests, tal como nos indica la Figura 131:

Figura 131Figura 131

SBien, en este momento tenemos tres tests en verde con la misma implementación que

realizamos para el primero de ellos. Sin embargo, ya es hora de pensar de otra forma:

disponemos de tres tests que prueban diferentes casos válidos, pero ¿qué pasa si creamos

instancias erróneas?

Probar las situaciones límites

Cuando se hacen tests es importante probar, también, las situaciones de límite.

Ejemplo: Si por alguna causa tenemos que probar que un determinado valor

esté entre 5 y 10, la forma correcta sería que escribamos, además de los tests

para los casos válidos, tests que especifi quen que 4 y 11 son casos inválidos.

En nuestro ejemplo actual enviamos varios mensajes (uno por transición) para crear una

defi nición completa, pero nos resulta imposible validar en cada envío de mensajes ya que

la estructura de datos no sería correcta en los estadios intermedios. La forma más simple

para implementar es pidiendo, explícitamente, a la defi nición que se valide a sí misma y

nos indique si es una instancia válida o no.

Seguimos, ahora modifi camos los tests agregando este código:Seguimos, ahora modifi camos los tests agregando este código:

self should:[defi niciónDeProceso esValida].

Page 72: Libro Smalltalk

142S

ProgramandoconSmalltalk

143S Manos a la obra

testLaMasSimpleDefi nición “Prueba la defi nición más simple posible” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar y terminar’ desde: ‘principio’ hasta: ‘fi n’.

self should:[defi niciónDeProceso esValida]. self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 1]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 2].

quedando estos de la siguiente manera:

testDefi niciónNoTrivial “Prueba una defi nición no trivlal” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘principio’ hasta: ‘A’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘A’

hasta: ‘B’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘anterior’ desde: ‘B’ hasta: ‘A’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘B’ hasta: ‘C’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘anterior’ desde: ‘C’ hasta: ‘B’.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘siguiente’ desde: ‘C’ hasta: ‘fi n’.

self should:[defi niciónDeProceso esValida]. self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 6]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 5].

A continuación, ejecutamos los tests como nos indica la Figura 132:

Figura 132Figura 132

SPrevisiblemente, el resultado es la obtención de 3 rojos. Bien, ahora presionamos sobre

cualquiera de los tests para obtener el pre-Depurador, después sobre el botón Create para

crear el método que falta en la clase Defi niciónDeProceso, dentro de la categoría testing

(ver Figura 133):

testDefi niciónSimple “Prueba una defi nición simple” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘A’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘A’ hasta: ‘fi n’.

self should:[defi niciónDeProceso esValida]. self should:[defi niciónDeProceso defi nicionesDeTransiciones size = 2]. self should:[defi niciónDeProceso defi nicionesDeEstados size = 3].

Page 73: Libro Smalltalk

144S

ProgramandoconSmalltalk

145S Manos a la obra

Figura 133Figura 133

Sy lo implementamos, por ahora (recordemos que hemos de escapar del rojo lo más rápido

posible), de la siguiente forma:

esValida “Responde si el receptor es una instancia válida” ^ true

Seguidamente, procedemos a cerrar el Depurador y ejecutamos todos los tests, como vemos

en la Figura 134:

Figura 134Figura 134

S

Ahora deberíamos escribir algunos tests que muestren cuáles son los casos inválidos. Por

ejemplo, uno de estos casos sería una defi nición de proceso que no tenga un estado inicial;

y lo volcamos en un test de la siguiente manera:

testDefi niciónSinPrincipio “Prueba una defi nición inválida que no tiene un estado inicial llamado ‘principio’” | defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘A’ hasta: ‘fi n’.

self shouldnt:[defi niciónDeProceso esValida].

Y lo ejecutamos, de nuevo, tal y como indica la Figura 135:

Figura 135Figura 135

SObservamos que hemos obtenido un test amarillo (que son los que no causan error, pero

en los que tampoco se cumplen todas las condiciones), hacemos clic sobre él y obtenemos

el pre-Depurador (ver Figura 136).

Figura 136Figura 136

S

Page 74: Libro Smalltalk

146S

ProgramandoconSmalltalk

147S Manos a la obra

Es importante saber que, cuando hacemos clic en un test de color amarillo, el framework

paraliza la ejecución en un punto anterior a nuestro test, lo que nos permite depurar paso

a paso el test antes de llegar a las condiciones. En este caso no nos interesa ejecutarlo

con tanto detalle, por lo que presionamos el botón Proceed para continuar y obtener el

Depurador en el mismo punto del fallo (ver Figura 137).

Figura 137Figura 137

SAhora la ejecución se detiene en el punto exacto del fallo y obtenemos el pre-Depurador para

poder indagar sobre lo que ha sucedido. Presionamos el botón Debug y buscamos, en el pa-

nel superior, el contexto de ejecución correspondiente a nuestro método (ver Figura 138).

Figura 138Figura 138

S

Vemos claramente que el fallo se da en la condición que no se cumple, por lo que se de-

muestra que hemos de implementar más funcionalidad en el método Defi niciónDe-

Proceso>>esValida.

A continuación, usando algún Browser, modifi camos el método Defi niciónDeProceso>>

esValida de la siguiente forma:de la siguiente forma:

esValida “Responde si el receptor es una instancia válida” self halt. ^ true

Hacemos clic sobre el test en amarillo y presionamos el botón Proceed en el pre-Depurador

(ver Figura 139).

Mensaje #halt

El mensaje #halt se puede enviar a cualquier objeto para que se active el Depurador,

al igual que a cualquier punto del código donde necesitemos un breakpoint (punto

de ruptura).

Figura 139Figura 139

SAhora, presionamos sobre el botón Debug y buscamos, en el Depurador, el contexto corres-

pondiente al método Defi niciónDeProceso>>esValida, como vemos en la Figura 140.

El Depurador nos ofrece más información a la hora de implementar

La implementación de un método en el Depurador tiene una ventaja muy im-

portante con respecto a hacerlo en los browser, y es la disposición del contexto

en el cual se activó el método.

Page 75: Libro Smalltalk

148S

ProgramandoconSmalltalk

149S Manos a la obra

De nuevo, volvemos a implementar el método de la siguiente forma:

La implementación de un método en el Depurador tiene una ventaja muy im-

portante con respecto a hacerlo en los browser, y es la disposición del contexto

en el cual se activó el método.

Además, disponemos de información sobre el receptor (en los dos paneles infe-

riores de la izquierda), información del contexto como argumentos y valores de

variables temporales (en los dos paneles inferiores a la derecha), información

de la pila de contextos (el call-stack), entre otros aspectos.

Y, fi nalmente, indicar que la modifi cación de algún método agregando un #halt

para que el Depurador nos muestre la información del contexto, también es una

costumbre muy extendida entre los programadores de Smalltalk.

esValida “Responde si el receptor es una instancia válida”

(self defi nicionesDeEstados includes: ‘principio’) ifFalse:[^ false].

^ true

Figura 140Figura 140

SDe nuevo, volvemos a implementar el método de la siguiente forma:

y ejecutamos los tests tal y como vemos en la Figura 141:

Figura 141Figura 141

SColecciones – mensaje #includes:

Responde si el objeto dado como argumento es uno de los elementos del receptor.

¡Verde! Nuestro autor ha caído en la cuenta que hemos cometido un error ortográfi co en el

nombre de método #esValida. Así que, nuevamente, utilizaremos una de las opciones del

Refactoring Browser para corregirlo y buscamos y seleccionamos el método en cuestión en

un Browser de Clases (ver Figura 142).

Figura 142Figura 142

S

Page 76: Libro Smalltalk

150S

ProgramandoconSmalltalk

151S Manos a la obra

Figura 143Figura 143

S

Ahora, pedimos el menú contextual sobre el método y seleccionamos la opción rename

method, siguiendo la secuencia que nos muestra la Figura 143.

A continuación, obtenemos una ventana que nos permite cambiar el nombre de método,

así como también modifi car el orden de los argumentos, si existieran (ver Figura 144).

SSegún observamos en la Figura 144, en el primer panel, donde indica esValida, escribimos

esVálida (esta vez con tilde), aceptamos con ALT-s y presionamos el botón OK. En este

momento, el Refactoring Browser ha cambiado el nombre del método corrigiendo todos los

métodos donde se ha enviado el mensaje #esValida.

Figura 145Figura 145

S

Figura 144

Para proceder a la validación de los cambios que ha realizado el Refactoring Browser,

presionamos el botón senders del Browser de Clases, seleccionamos esVálida y vemos qué

métodos de toda la imagen envían ese mensaje (ver Figura 145).

Senders

La función senders (disponible como un botón dentro de los Browser, o como op-

ción del menú contextual sobre el método o presionando ALT-n) nos ofrece un bus-

cador con todos los métodos de la imagen que envíen dicho mensaje.

Se trata de una de la principales herramientas para buscar en Smalltalk. Así, cada caso

que nos muestra el senders es un ejemplo de uso del mensaje, pero no un ejemplo

cualquiera, sino que son ejemplos que están funcionando en la imagen y que, si fuese

necesario, podríamos depurar paso a paso. Por tanto, es mucho más útil que una do-

cumentación estática en algún archivo externo.

Figura 144

Page 77: Libro Smalltalk

152S

ProgramandoconSmalltalk

153S Manos a la obra

Figura 146Figura 146

SAhora que estamos en verde, es el momento de limpiar el código que acabamos de generar,

y lo hacemos del siguiente modo:

esVálida “Responde si el receptor es una instancia válida”

(self defi nicionesDeEstados includes: ‘principio’) ifFalse: [^false]. ^true

Una de las causas que restan claridad en el código es el uso de constantes mágicas, que son

constantes (muchas veces un literal) que aparecen en el código sin más, sin especifi car su

signifi cado. Para evitarlo, vamos a utilizar el patrón Constant Method.

Llegados a este punto, deberíamos ejecutar, nuevamente, los tests para asegurarnos que

todo está correcto (ver Figura 146).

Constant Method (Método Constante)

¿Cómo se puede codifi car una constante ofreciendo información sobre su signifi cado?

Muy sencillo, simplemente creando un método que devuelva la constante; aprovecharse

del nombre del método y el comentario de éste para explicar el verdadero signifi cado de la

constante.Más información en el libro: “Smalltalk Best Practice Patterns” (ver bibliografía).

De nuevo, vamos a servirnos de una de las funcionalidades del Refactoring Browser (¡a

nuestro autor le entusiasma el Refactoring Browser!). Para ello, seleccionamos la parte que

corresponde a la constante, pedimos el menú contextual y elegimos la opción extract

method, tal y como nos muestra la Figura 147.

Figura 147Figura 147

SUna vez aquí, añadimos el nombre del método (de la misma forma en que lo hicimos cuando

cambiamos el nombre al método #esValida), nombreDeEstadoInicial (ver Figura 148).

Figura 148Figura 148

S

Page 78: Libro Smalltalk

154S

ProgramandoconSmalltalk

155S Manos a la obra

Figura 150Figura 150

S

Aceptamos (con ALT-s) y presionamos sobre ENTER. El resultado lo tenemos en la Figura

149, donde vemos cómo queda el método.

Figura 149Figura 149

SLa Figura 150 nos muestra la apariencia del método recién creado:

Ahora, comentamos el método de la siguiente forma:

nombreDeEstadoInicial “Responde el nombre del estado inicial”

^ ‘principio’

Seguimos introduciendo los casos inválidos y hacemos lo mismo para el estado fi nal:

testDefi niciónSinFinal “Prueba una defi nición inválida que no tiene un estado fi nal llamado ‘fi n’”

| defi niciónDeProceso | defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘A’. self shouldnt: [defi niciónDeProceso esVálida]

Obtenemos el amarillo y, justo en el siguiente punto, implementamos la funcionalidad de

forma análoga a la anterior.

esVálida “Responde si el receptor es una instancia válida”

(self defi nicionesDeEstados includes: self nombreDeEstadoInicial) ifFalse: [^false].

(self defi nicionesDeEstados includes: self nombreDeEstadoFinal) ifFalse: [^false].

^true

nombreDeEstadoFinal “Responde el nombre del estado fi nal”

^ ‘fi n’

Ejecutamos los tests y, nuevamente, estamos en verde (ver Figura 151):

Figura 151Figura 151

S155SS Manos a la obra

Page 79: Libro Smalltalk

156S

ProgramandoconSmalltalk

157S Manos a la obra

Nos olvidamos de, tal vez, el caso inválido más simple: una defi nición sin transiciones ni

estados:

testDefi niciónVacía “Prueba una defi nición inválida por estar vacía”

| defi niciónDeProceso | defi niciónDeProceso := Defi niciónDeProceso new. self shouldnt: [defi niciónDeProceso esVálida]

y ejecutamos los tests tal y como vemos en la Figura 152:

Seguidamente, hacemos clic sobre el test que muestra el error y abrimos el Depurador para

comprobar qué es lo que ha sucedido (ver Figura 153).

De nuevo, nos encontramos ante el caso donde la variable de instancia transiciones no

está inicializada. Si recordamos, el caso anterior lo resolvimos con lazy-initialization en el

método #agregarDefi niciónDeTransición:desde:hasta:, pero ahora no podemos hacerlo

así porque no hemos invocado dicho método. Por esto, vamos a mover la inicialización de

esa variable al método #initialize dentro de la categoría initialization (ver Figura 154):

Figura 152Figura 152

SFigura 154Figura 154

S

Figura 153Figura 153

S

y removemos el lazy-initialization que hicimos anteriormente, tal y como nos muestra la

Figura 155:

Page 80: Libro Smalltalk

158S

ProgramandoconSmalltalk

159S Manos a la obra

Figura 155Figura 155

SComo viene siendo habitual en todo el proceso, volvemos a ejecutar los tests (ver Figura 156).

Figura 156Figura 156

SLos tests son, también, documentación

Si respetamos las simples reglas que dominan el TDD, no obtendremos ninguna

funcionalidad en el software desarrollado que no tenga, como mínimo, un test que

la valide. Esto implica que el conjunto de los test de un sistema son una excelente

documentación.

Los tests componen una documentación que se puede, además de leer, ejecutar en

el depurador paso a paso. También sabemos a ciencia cierta si esa documentación

está actualizada o no, según el test esté en verde o en rojo. Y, por si fuera poco, los

tests son documentación que se escribe a la vez que se desarrolla el sistema.

Para mejorar la documentación del sistema que estamos desarrollando, vamos a categorizar

de nuevo los tests para indicar cuáles corresponden a instanciaciones válidas y cuales a

inválidas. Bien, usamos el Browser de Clases para crear dos nuevas Categorías de Métodos:

running - instancias válidas y running - instancias inválidas (menú contextual del panel

de Categorías de Métodos, opción new category...).

Figura 157Figura 157

SAhora, arrastramos el método (desde el panel de Métodos) hasta la categoría donde

queremos incluirlo, reorganizamos los métodos y, con la opción remove empty categories

del menú contextual del panel de Categorías, borramos la categoría vacía.

Seguimos con la implementación. Otra condición que han de cumplir las defi niciones

de proceso para ser válidas, es que el estado inicial sea realmente el primero, por lo que

escribimos otro test con esta condición:

testDefi niciónPrincipioInválido “Prueba una defi nición donde el estado inicial no es realmente el inicial”

| defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘A’ hasta: ‘principio’.

Page 81: Libro Smalltalk

160S

ProgramandoconSmalltalk

161S Manos a la obra

A continuación, ejecutamos los tests y obtenemos el amarillo esperado. Para saber si el

estado inicial es realmente el inicial, como hemos dicho más arriba, debemos asegurarnos

que ninguna transición tenga ese estado como destino.

Así, pues, modifi camos el método #esVálida de la siguiente forma.

esVálida “Responde si el receptor es una instancia válida”

(self defi nicionesDeEstados includes: self nombreDeEstadoInicial) ifFalse: [^false].

(self defi nicionesDeEstados includes: self nombreDeEstadoFinal) ifFalse: [^false].

(transiciones anySatisfy: [:each | each third = self nombreDeEstadoInicial]) ifTrue: [^false].

^true

Colecciones – mensaje #anySatisfy:

Evalúa el bloque con los elementos del receptor. Si el bloque responde true (verda-

dero) para cualquiera de los elementos, devuelve true, si no, devuelve false (falso).

Como siempre, ejecutamos los tests y estamos en verde de nuevo.

De la misma forma, tenemos que asegurarnos que el estado fi nal sea realmente el estado

fi nal. Para ello, escribimos otro test:

defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘principio’ hasta: ‘fi n’.

self shouldnt: [defi niciónDeProceso esVálida]

testDefi niciónFinalInválido “Prueba una defi nición donde el estado fi nal no es realmente el fi nal”

| defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new.

defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘fi n’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘fi n’ hasta: ‘A’.

self shouldnt: [defi niciónDeProceso esVálida]

Ahora, la ejecución de los tests nos lleva al amarillo.

esVálida “Responde si el receptor es una instancia válida”

(self defi nicionesDeEstados includes: self nombreDeEstadoInicial) ifFalse: [^false].

(self defi nicionesDeEstados includes: self nombreDeEstadoFinal) ifFalse: [^false].

(transiciones anySatisfy: [:each | each third = self nombreDeEstadoInicial]) ifTrue: [^false].

(transiciones anySatisfy: [:each | each second = self nombreDeEstadoFinal]) ifTrue: [^false].

^true

Tras esta operación, nos encontramos nuevamente con el verde, pero la claridad del método

#esVálida es bastante confusa, así que, procedemos a limpiarlo.

Además, vemos que las expresiones que determinan los cuatro casos inválidos son un poco

crípticas, por lo que vamos a hacer uso del patrón Composed Method, que explicamos a

continuación.

Composed Method (Método Compuesto)

¿Cómo se divide un programa en métodos? Esto se consigue fraccionando el

programa en métodos que lleven a cabo una tarea bien identifi cable y manteniendo

todas las operaciones de un método en el mismo nivel de abstracción.

Más información en el libro: “Smalltalk Best Practice Patterns” (ver bibliografía).

Page 82: Libro Smalltalk

162S

ProgramandoconSmalltalk

163S Manos a la obra

En este punto, usaremos, nuevamente, la funcionalidad extract method del Refactoring

Browser para desmenuzar el método de mayor tamaño en pequeñas partes. Para ello,

primero seleccionamos la expresión de la primera condición (ver Figura 158):

y la extraemos a un método llamado tieneEstadoInicial. Hacemos lo mismo para la

siguiente expresión, extrayéndola en un método llamado tieneEstadoFinal.

Figura 158Figura 158

SSeguimos con la siguiente expresión y la sacamos a un método llamado llegaAlguna-

TransicionAlEstadoInicial. Del mismo modo, operamos igual para la última condición,

extrayéndola a un método de nombre saleAlgunaTransicionDelEstadoFinal.

El método, ahora, se muestra como verdadera documentación:

esVálida “Responde si el receptor es una instancia válida”

self tieneEstadoInicial ifFalse: [^false]. self tieneEstadoFinal ifFalse: [^false]. self llegaAlgunaTransicionAlEstadoInicial ifTrue: [^false]. self saleAlgunaTransicionDelEstadoFinal ifTrue: [^false]. ^true

y comentamos los métodos extraídos por el Refactoring Browser:

tieneEstadoInicial “Responde si el receptor tiene algún estado inicial”

^self defi nicionesDeEstados includes: self nombreDeEstadoInicial

A continuación, volvemos a ejecutar los tests y seguimos en verde (ver Figura 159).

tieneEstadoFinal “Responde si el receptor tiene algún estado fi nal”

^self defi nicionesDeEstados includes: self nombreDeEstadoFinal

llegaAlgunaTransicionAlEstadoInicial “Responde si alguna transición del receptor tiene como llegada el estado inicial”

^transiciones anySatisfy: [:each | each third = self nombreDeEstadoInicial]

saleAlgunaTransicionDelEstadoFinal “Responde si alguna transición del receptor tiene como partida el estado fi nal”

^transiciones anySatisfy: [:each | each second = self nombreDeEstadoFinal]

Figura 159Figura 159

SSHasta este momento tenemos guardada toda la información de las transiciones en un

Array, que no es algo muy orientado a objetos, así que vamos a cambiar el método #agre-

garDefi niciónDeTransición:desde:hasta: de la siguiente forma:

Page 83: Libro Smalltalk

164S

ProgramandoconSmalltalk

165S Manos a la obra

agregarDefi niciónDeTransición: transiciónString desde: estadoDesdeString hasta: estadoHastaString

“Agrega una defi nición de transición con el nombre dado, que une dos estados de nombres dados”

| transición |

transición := Defi niciónDeTransición nombre: transiciónString desde: estadoDesdeString hasta: estadoHastaString.

transiciones add: transición

Al aceptar, creamos la clase Defi niciónDeTransición, en la categoría de clases Workfl ow,y

confi rmamos que el selector #nombre:desde:hasta: es correcto.

Ejecutamos los tests, como es habitual (ver Figura 160).

Figura 160Figura 160

SSAhora elegimos alguno de los tests marcados en rojo para arreglarlo. Nuestro autor propone

comenzar por #testLaMasSimpleDefi nición, ya que parece ser el caso más sencillo de

solucionar. Para ello, pedimos el Depurador sobre ese test con un clic en el panel inferior

(ver Figura 161):

Figura 161Figura 161

SSy creamos el método en la clase Defi niciónDeTransición class, dentro de la categoría de

métodos llamada instance creation, implementándolo de la siguiente manera:

nombre: nombreString desde: desdeString hasta: hastaString “Responde una nueva instancia del receptor”

^ self new initializeNombre: nombreString desde: desdeString hasta: hastaString

Aceptamos y continuamos con nuestro ejemplo.

Ahora debemos aplicar el método #initializeNombre:desde:hasta: en la clase Defi nición-

DeTransición, dentro de la nueva categoría de nombre initialization, de este modo:

initializeNombre: nombreString desde: desdeString hasta: hastaString “Inicializa el receptor”

nombre := nombreString. desde := desdeString. hasta := hastaString.

defi nicionesDeEstados “Responde las defi niciones de estados del receptor”

| estadosDesde estadosHasta | estadosDesde := transiciones collect: [:each | each desde]. estadosHasta := transiciones collect: [:each | each hasta]. ^ (estadosDesde , estadosHasta) asSet.

y creamos las variables de instancia nombre, desde y hasta al aceptar.

De nuevo, detectamos que un objeto de clase Defi niciónDeTransición no entiende el

mensaje #second, aunque esto es lógico porque hemos reemplazado un Array por una de

nuestras clases. Bien, procedemos a modifi car el método #defi nicionesDeEstados de la

siguiente forma:

Page 84: Libro Smalltalk

166S

ProgramandoconSmalltalk

167S Manos a la obra

desde “Responde el nombre de estado de partida del receptor” ^ desde

hasta “Responde el nombre de estado de llegada del receptor” ^ hasta

Como siempre, aceptamos y seguimos trabajando. Ahora, debemos aplicar los métodos

#desde y #hasta en la clase Defi niciónDeTransición, dentro de la categoría accessing con

las siguientes órdenes:

A continuación, observamos que nuestra clase no entiende el mensaje #third. Para solu-

cionarlo, volvemos a modifi car el método #llegaAlgunaTransicionAlEstadoInicial de la

siguiente forma:

llegaAlgunaTransicionAlEstadoInicial “Responde si alguna transición del receptor tiene como llegada el estado inicial”

^transiciones anySatisfy: [:each | each hasta = self nombreDeEstadoInicial]

saleAlgunaTransicionDelEstadoFinal “Responde si alguna transición del receptor tiene como partida el estado fi nal”

^transiciones anySatisfy: [:each | each desde = self nombreDeEstadoFinal]

y cambiamos el método #saleAlgunaTransicionDelEstadoFinal con estas instrucciones:

Figura 162Figura 162

S166SS

Continuamos, pero ahora vamos a ejecutar todos los tests para saber qué es lo que tenemos

que arreglar de nuevo (ver Figura 162).

Los tests aumentan la confi anza

¿Cuántas veces hemos dudado en cambiar código erróneamente escrito, pero no lo

hemos hecho por miedo a romper el sistema?

Los sistemas desarrollados con TDD están controlados por decenas, incluso cente-

nares, de tests. Podemos estar prácticamente seguros que, si refactorizamos algo y

los tests funcionan, entonces, no hemos alterado el comportamiento del código.

¡Perfecto! Ya no queda nada por arreglar.

testDefi niciónConEstadosInalcanzables “Prueba una defi nición donde hay estados que no se pueden alcanzar desde el estado inicial”

| defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar y terminar’ desde: ‘principio’ hasta: ‘fi n’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘A’ hasta: ‘fi n’.

self shouldnt: [defi niciónDeProceso esVálida]

Después, ejecutamos los tests y estamos, de nuevo, en amarillo. Así, vamos a modifi car el

método #esVálida de la siguiente forma:

esVálida “Responde si el receptor es una instancia válida”

self tieneEstadoInicial ifFalse: [^false]. self tieneEstadoFinal ifFalse: [^false]. self llegaAlgunaTransicionAlEstadoInicial ifTrue: [^false]. self saleAlgunaTransicionDelEstadoFinal ifTrue: [^false]. self tieneEstadosInalcanzables ifTrue:[^false]. ^true

Page 85: Libro Smalltalk

168S

ProgramandoconSmalltalk

169S Manos a la obra

tieneEstadosInalcanzables “Responde si el receptor tiene estados inalcanzables desde el estado inicial”

^ self estadosInalcanzables notEmpty

Seguidamente, implementamos el método #estadosInalcanzables dentro de la categoría

accessing con estas órdenes:

estadosInalcanzables “Responde los estados inalcanzables desde el estado inicial”

^ self defi nicionesDeEstados copyWithoutAll: self estadosAlcanzables

al igual que el método #estadosAlcanzables, también en la misma categoría:

estadosAlcanzables “Responde los estados alcanzables desde el estado inicial”

| aVisitar resultado |

aVisitar := OrderedCollection with: self nombreDeEstadoInicial. resultado := aVisitar asSet.

[aVisitar isEmpty] whileFalse: [ | actual nuevos |

actual := aVisitar removeFirst. nuevos := (self estadosAlcanzablesDesde: actual) copyWithoutAll: resultado.

resultado addAll: nuevos. aVisitar addAll: nuevos. ].

^ resultado

y, fi nalmente, el método #estadosAlcanzablesDesde: en la categoría accessing.

Como nuestro propósito, en este momento, es implementar el método #tieneEstados-

Inalcanzables en la categoría testing, ejecutamos los tests para invocar al pre-Depurador y

ejecutar esta acción:

estadosAlcanzablesDesde: aDefi niciónDeEstado “Responde los estados alcanzables desde el estado dado”

^ transiciones select:[:each | each desde = aDefi niciónDeEstado] thenCollect:[:each | each hasta]

Colecciones – mensaje #select:thenCollect

Mensaje de utilidad que se comporta como un #select: seguido de un #collect:.

Colecciones – mensaje #select

Evalúa el bloque dado por cada elemento del receptor como argumento; colecciona

los elementos en los que el bloque evalúa a true (verdadero) en una colección del

tipo del receptor y responde esa colección nueva como resultado.

Ejemplos:.

‘Un String’ select: [:each | each isUppercase].

#(1 2 3 4 5 6 7 8 9 10) select: [:each | each odd].

Smalltalk allClasses select:[:each | each superclass == TestCase].

Volvemos a estar en verde, tal y como nos indica la Figura 163.

Figura 163

169SS Manos a la obra

Figura 163

S

Page 86: Libro Smalltalk

170S

ProgramandoconSmalltalk

171S Manos a la obra

El último código que hemos escrito no ha quedado muy orientado a objetos precisamente.

Esto se ha debido, sobre todo, a que todavía no hemos creado una clase para representar las

defi niciones de estado, por lo que estamos manipulando strings. Vamos a crear, entonces,

la clase que corresponde y comenzamos modifi cando el método Defi niciónDeProceso>>

agregarDefi niciónDeTransición:desde:hasta: de la siguiente forma:

agregarDefi niciónDeTransición: transiciónString desde: estadoDesdeString hasta: estadoHastaString

“Agrega una defi nición de transición con el nombre dado, que une dos estados de nombres dados”

| estadoDesde estadoHasta transición |

estadoDesde := self estadoDeNombre: estadoDesdeString. estadoHasta := self estadoDeNombre: estadoHastaString.

transición := Defi niciónDeTransición nombre: transiciónString desde: estadoDesde hasta: estadoHasta.

transiciones add: transición

Ejecutamos los tests y vemos que casi todos fallan. Para solucionarlo, hacemos clic sobre

alguno de los tests en rojo para implementar desde el Depurador.

A continuación, creamos el método #estadoDeNombre:, en la categoría accessing, del

siguiente modo:

estadoDeNombre: aString “Responde un estado de nombre dado. Crea uno nuevo si es necesario.”

^ estados at: aString ifAbsentPut:[Defi niciónDeEstado nombre: aString].

Colecciones – mensaje #at:ifAbsentPut:

Responde el elemento de nombre dado. En el caso que no haya ningún elemento

con ese nombre, se evalúa el bloque dado y el resultado de dicha evaluación se guar-

da en el receptor y se responde al remitente.

Ahora, la nueva variable de instancia estados tendrá un diccionario, por lo que que

modifi camos el método Defi niciónDeProceso>>initialize de la siguiente forma:

initialize “Inicializa el receptor”

transiciones := Set new. estados := Dictionary new.

Colecciones – Dictionary

El Dictionary (Diccionario) es una colección que puede verse desde dos

perspectivas:

ß Como un Set de asociaciones clave->valor.

ß Como un contenedor donde los elementos son nombrados desde el exterior y el

nombre puede ser cualquier objeto que responda al mensaje #=.

Ejemplos: “instanciar, y llenar, un diccionario” | diccionario |

diccionario := Dictionary new.

diccionario at: ‘hoy’ put: Date today. diccionario at: ‘ahora’ put: Time now. diccionario at: false put: ‘es false’.

“algunas formas de acceder al diccionario” diccionario at: ‘hoy’. diccionario at: ‘mañana’ ifAbsent:[nil]. diccionario at: ‘mañana’. diccionario at: ‘mañana’ ifAbsentPut:[Date tomorrow]. diccionario at: ‘mañana’.

“otras formas de acceso” diccionario keys. diccionario values.

“algunas iteraciones” Transcript clear.

Creado el método, generamos la variable de instancia estados y la clase Defi niciónDeEs-

tado en la categoría Workfl ow.

Page 87: Libro Smalltalk

172S

ProgramandoconSmalltalk

173S Manos a la obra

Transcript cr; show: ‘#do:’; cr. diccionario do: [:each | Transcript show: ‘ ‘ , each asString; cr. ].

Transcript cr; show: ‘#associationsDo:’; cr. diccionario associationsDo: [:each | Transcript show: ‘ ‘ , each asString; cr. ].

Transcript cr; show: ‘#keysAndValuesDo:’; cr. diccionario keysAndValuesDo:[:eachKey :eachValue | Transcript show: ‘ ‘ , eachKey asString , ‘ - ‘ , eachValue asString; cr. ].

Implementamos el método Defi niciónDeProceso class>>nombre:, en la categoría

instance creation, de la siguiente forma:

Transcript

Transcript es una variable global que apunta a una ventana de Transcript (siempre

que esté abierta), y normalmente se usa para mostrar pequeños mensajes que ayu-

dan a la depuración del código.

Para obtener una ventana de Transcript seguimos la secuencia: menú del Mundo |

open... | transcript (t) (o presionar ALT-t).

Por tanto, el Transcript responde a una serie de mensajes muy útiles a la hora de

depurar:

ß #show: muestra el argumento, convertido a String, en la ventana.

ß #cr hace un salto de línea en la ventana.

ß #clear limpia el contenido de la ventana.

, de la siguiente forma:

nombre: aString “Responde una nueva instancia del receptor”

^ self new initializeNombre: aString

y volvemos a implementar, pero ahora, el método Defi niciónDeProceso>>initializeNombre:,

en la nueva categoría initialization, así:

y creamos la variable de instancia nombre.

Continuamos con el proceso ejecutando los tests y, otra vez, estamos en amarillo, tal y

como vemos en la Figura 164.

y creamos la variable de instancia nombre

initializeNombre: aString “Inicializa el receptor”

nombre := aString

Figura 164Figura 164

S¿Qué ha sucedido? Hasta este momento veníamos utilizando sólo un String en lugar de

un objeto de clase Defi niciónDeEstado para los estados y dos constantes (también String)

para los estados especiales, inicial y fi nal. Si buscamos los senders de ambos métodos de

constante (Constant Method) #nombreDeEstadoInicial y #nombreDeEstadoFinal), segu-

ramente encontraremos las líneas que hemos de modifi car.

Para encontrar los senders de #nombreDeEstadoInicial podemos usar la opción senders

of... (n ) del menú contextual del panel de Métodos en un Browser de Clases, tal y como nos

indica la Figura 165:

Page 88: Libro Smalltalk

174S

ProgramandoconSmalltalk

175S Manos a la obra

y obtenemos un Browser como el que vemos en la Figura 166:

Figura 165

y obtenemos un como el que vemos en la

Figura 165

SSFigura 166Figura 166

SPero nos encontramos con dos métodos que tenemos que cambiar, así que repetimos el

procedimiento para #nombreDeEstadoInicial y, de nuevo, tenemos otros tres métodos

que arreglar. Por ello, tecleamos estas órdenes para ejecutar el arreglo:

tieneEstadoInicial “Responde si el receptor tiene algún estado inicial”

^self defi nicionesDeEstados anySatisfy:[:each | each nombre = self nombreDeEstadoInicial]

tieneEstadoFinal “Responde si el receptor tiene algún estado fi nal”

^self defi nicionesDeEstados anySatisfy:[:each | each nombre = self nombreDeEstadoFinal]

llegaAlgunaTransicionAlEstadoInicial “Responde si alguna transición del receptor tiene como llegada el estado inicial”

^transiciones anySatisfy: [:each | each hasta nombre = self nombreDeEstadoInicial]

saleAlgunaTransicionDelEstadoFinal “Responde si alguna transición del receptor tiene como partida el estado fi nal”

^transiciones anySatisfy: [:each | each desde nombre = self nombreDeEstadoFinal]

estadosAlcanzables “Responde los estados alcanzables desde el estado inicial”

| aVisitar resultado |

aVisitar := OrderedCollection with: (self estadoDeNombre: self nombreDeEstadoInicial). resultado := aVisitar asSet.

[aVisitar isEmpty] whileFalse: [ | actual nuevos |

actual := aVisitar removeFirst. nuevos := (self estadosAlcanzablesDesde: actual) copyWithoutAll: resultado.

resultado addAll: nuevos. aVisitar addAll: nuevos. ].

^ resultado

Page 89: Libro Smalltalk

176S

ProgramandoconSmalltalk

177S Manos a la obra

Nuevamente estamos en verde, así que es momento de limpiar el código.

La anterior implementación del método Defi niciónDeProceso>>defi nicionesDeEstados

puede ser reemplazada por la siguiente:

y seguimos en verde. La siguiente expresión, que introdujimos en el método Defi niciónD

eProceso>>estados-Alcanzables, es la mejor candidata para un Extract Method.

Lo ejecutamos y dejamos los métodos de esta manera:

nombre “Responde el nombre del receptor” ^ nombre

defi nicionesDeEstados “Responde las defi niciones de estados del receptor”

^ estados values

(self estadoDeNombre: self nombreDeEstadoInicial)

estadosAlcanzables “Responde los estados alcanzables desde el estado inicial”

| aVisitar resultado |

aVisitar := OrderedCollection with: self estadoInicial. resultado := aVisitar asSet.

[aVisitar isEmpty] whileFalse: [ | actual nuevos |

actual := aVisitar removeFirst. nuevos := (self estadosAlcanzablesDesde: actual) copyWithoutAll: resultado.

resultado addAll: nuevos. aVisitar addAll: nuevos. ].

^ resultado

e implementamos el método Defi niciónDeProceso>>nombre, en la categoría accessing.

Podemos refactorizar otros senders de #nombreDeEstadoInicial para aprovecharnos del

nuevo método creado y evitar comparaciones por nombre.

estadoInicial “Responde el estado inicial”

^ self estadoDeNombre: self nombreDeEstadoInicial

llegaAlgunaTransicionAlEstadoInicial “Responde si alguna transición del receptor tiene como llegada el estado inicial”

^transiciones anySatisfy: [:each | each hasta = self estadoInicial]

Seguidamente, hacemos lo mismo para el estado fi nal:

estadoFinal “Responde el estado fi nal”

^ self estadoDeNombre: self nombreDeEstadoFinal

y seguimos en verde, pero con el código un poco más limpio.

Finalmente, lo último que debemos validar es que no exista más de una transición con el

mismo nombre para el estado de salida o, lo que es lo mismo, la combinación estadoDesde-

nombreDeTransición debe ser única. Llevamos a la práctica esta explicación en un test:

testDefi niciónConTransicionesDuplicadas “Prueba una defi nición donde hay transiciones con el mismo nombre que salen de un determinado estado”

| defi niciónDeProceso |

defi niciónDeProceso := Defi niciónDeProceso new.

defi niciónDeProceso

saleAlgunaTransicionDelEstadoFinal “Responde si alguna transición del receptor tiene como partida el estado fi nal”

^transiciones anySatisfy: [:each | each desde = self estadoFinal]

Page 90: Libro Smalltalk

178S

ProgramandoconSmalltalk

179S Manos a la obra

agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘fi n’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar’ desde: ‘principio’ hasta: ‘A’. defi niciónDeProceso agregarDefi niciónDeTransición: ‘terminar’ desde: ‘A’ hasta: ‘fi n’.

self shouldnt: [defi niciónDeProceso esVálida]

y obtenemos el amarillo, lo que nos lleva a implementar lo que vemos a continuación:

esVálida “Responde si el receptor es una instancia válida”

self tieneEstadoInicial ifFalse: [^false]. self tieneEstadoFinal ifFalse: [^false]. self llegaAlgunaTransicionAlEstadoInicial ifTrue: [^false]. self saleAlgunaTransicionDelEstadoFinal ifTrue: [^false]. self tieneEstadosInalcanzables ifTrue:[^false]. self tieneAlgunEstadoConTransicionesDuplicadas ifTrue:[^false]. ^true

tieneAlgunEstadoConTransicionesDuplicadas “Responde si el receptor tiene algún estado con transiciones duplicadas “ ^ self defi nicionesDeEstados anySatisfy: [:eachEstado | | transicionesDesde nombresDesde | transicionesDesde := self transicionesDesde: eachEstado. nombresDesde := transicionesDesde collect: [:eachTransicion | eachTransicion nombre]. transicionesDesde size ~= nombresDesde asSet size ]

transicionesDesde: aDefi niciónDeEstado “Responde las transiciones que tienen el estado dado como ‘desde’” ^ transiciones select:[:each | each desde = aDefi niciónDeEstado]

nombre “Responde el nombre del receptor” ^ nombre

Tras esta ejecución, estamos en verde.

Figura 167Figura 167

SAhora deberíamos mover la funcionalidad que tenemos en Defi nicióndeProceso, pero

que le corresponde a la recién creada clase Defi niciónDeEstado.

Para mover dicha funcionalidad vamos a modifi car la instanciación de las transiciones.

Para ello, haremos que la transición informe a cada uno de los estados involucrados

sobre su propia existencia para que estos, a su vez, conozcan la estructura de la cual

forman parte.

Así, cambiamos los nombres de los argumentos en el constructor Defi niciónDeTransición,

indicando que ahora esperamos objetos Defi niciónDeEstado y no objetos String.

nombre: nombreString desde: desdeDefi niciónDeEstado hasta: hastaDefi niciónDeEstado “Responde una nueva instancia del receptor”

^ self new initializeNombre: nombreString desde: desdeDefi niciónDeEstado hasta: hastaDefi niciónDeEstado

Seguidamente, modifi camos el método de inicialización arreglando, también, los nombres

de los argumentos y notifi cando a las defi niciones de estado la transición recién creada.

Page 91: Libro Smalltalk

180S

ProgramandoconSmalltalk

181S Manos a la obra

nuevaTransiciónSaliente: aDefi niciónDeTransición “Agrega, en la colección de transiciones salientes del receptor, la defi nición de transición dada”

transicionesSalientes add: aDefi niciónDeTransición

nuevaTransiciónEntrante: aDefi niciónDeTransición “Agrega, en la colección de transiciones entrantes del receptor, la defi nición de transición dada”

transicionesEntrantes add: aDefi niciónDeTransición

initialize “Inicializa al receptor” transicionesSalientes := Set new. transicionesEntrantes := Set new.

estadosAlcanzables “Responde los estados alcanzables desde el receptor”

^ transicionesSalientes collect:[:each | each hasta]

Ahora, implementamos el método #estadosAlcanzables, en la clase Defi niciónDeEstado,

que reemplazará al método Defi niciónDeProceso>>estadosAlcanzablesDesde:.

e inicializamos las recién creadas variables de instancia:

Continuamos implementando los métodos #nuevaTransiciónSaliente: y #nuevaTran-

siciónEntrante:, dentro de la clase Defi niciónDeEstado, creándose así las dos nuevas

variables de instancia necesarias:

initializeNombre: nombreString desde: desdeDefi niciónDeEstado hasta: hastaDefi niciónDeEstado “Inicializa el receptor”

nombre := nombreString. desde := desdeDefi niciónDeEstado. hasta := hastaDefi niciónDeEstado.

desde nuevaTransiciónSaliente: self. hasta nuevaTransiciónEntrante: self.

Por tanto, vamos a modifi car el método Defi niciónDeProceso>>estadosAlcanzables con

las siguientes instrucciones:

estadosAlcanzables “Responde los estados alcanzables desde el estado inicial”

| aVisitar resultado |

aVisitar := OrderedCollection with: self estadoInicial. resultado := aVisitar asSet.

[aVisitar isEmpty] whileFalse: [ | actual nuevos |

actual := aVisitar removeFirst. nuevos := actual estadosAlcanzables copyWithoutAll: resultado.

resultado addAll: nuevos. aVisitar addAll: nuevos. ].

^ resultado

Procedemos a borrar el método Defi niciónDeProceso>>estadosAlcanzablesDesde: a

través del menú contextual sobre el panel de Métodos | remove method (x) y ejecutamos

los tests. En este momento, estamos de nuevo en verde.

Otra funcionalidad que debemos mover es la prueba por transiciones salientes duplica-

das, para lo que agregamos el siguiente método en la clase Defi niciónDeEstado.

tieneTransicionesDuplicadas

“Responde si el receptor tiene más de 1 transición saliente con el mismo nombre”

| nombres |

nombres := (transicionesSalientes collect:[:each | each nombre]) asSet.

^ transicionesSalientes size ~= nombres size

Tras esta operación, cambiamos el siguiente método en la clase Defi niciónDeProceso con

estas órdenes:

Page 92: Libro Smalltalk

182S

ProgramandoconSmalltalk

183S Manos a la obra

tieneAlgunEstadoConTransicionesDuplicadas “Responde si el receptor tiene algún estado con transiciones duplicadas “ ^ self defi nicionesDeEstados anySatisfy: [:each | each tieneTransicionesDuplicadas]

Al aceptar el método, creamos la clase Proceso, en la categoría Workfl ow.

A continuación, ejecutamos los tests y, previsiblemente, estamos en rojo. Después, creamos

el método #nuevaInstancia en la clase Defi niciónDeProceso, dentro de la nueva categoría

instancias.

testLaMasSimpleInstanciaDeProceso “Prueba la defi nición más simple posible, con su instancia”

| defi niciónDeProceso defi niciónEstadoInicial proceso |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar y terminar’ desde: ‘principio’ hasta: ‘fi n’.

defi niciónEstadoInicial := defi niciónDeProceso estadoInicial.

proceso := defi niciónDeProceso nuevaInstancia. self should:[proceso class = Proceso]. self should:[proceso estado defi nición = defi niciónEstadoInicial].

y borramos el método Defi niciónDeProceso>>transicionesDesde:.

De nuevo, ejecutamos los tests y seguimos en verde, pero esta vez el código está mucho más

orientado a objetos.

Ha llegado la hora de hacer algo con las Defi niciones de Proceso. Bien, lo primero que tiene

que hacer una Defi nición de Proceso es crear una Instancia de Proceso. Sólo una aclaración:

cuando hablamos de Instancia de Proceso estamos usando terminología de Workfl ow, por

lo que no nos referimos a instancias de Smalltalk.

La Instancia de Proceso más simple que se le ocurre a nuestro autor es la siguiente:

nuevaInstancia “Crea una nueva instancia de proceso”

^ Proceso defi nición: self.

defi nición: aDefi niciónDeProceso “Crea una nueva instancia del receptor”

^ self new initializeDefi nición: aDefi niciónDeProceso

Procedemos a crear el método Proceso class>>defi nición:, en la categoría instance crea-

tion, de la siguiente forma:

y el método Proceso>>initializeDefi nición: en la categoría initialization.

Aceptamos, creándose así la variable de instancia defi nición. Ahora debemos implementar

el método Defi niciónDeProceso>>estado.

Las instancias de proceso siempre tienen un estado asociado. Así, los procesos recién em-

pezados se encuentran en el estado inicial y, los procesos terminados, en el estado fi nal.

Dicho esto, modifi camos el método Proceso>>initializeDefi nición: así:

initializeDefi nición: aDefi niciónDeProceso “Inicializa la defi nición del receptor”

defi nición := aDefi niciónDeProceso

initializeDefi nición: aDefi niciónDeProceso “Inicializa la defi nición del receptor”

defi nición := aDefi niciónDeProceso.

estado := defi nición estadoInicial nuevaInstancia.

y creamos la variable de instancia estado al aceptar. Del mismo modo, generamos el

siguiente método:

Page 93: Libro Smalltalk

184S

ProgramandoconSmalltalk

185S Manos a la obra

Y seguimos creando, ahora, este método en la clase Defi niciónDeEstado, en la categoría

instancias:

Al aceptar, creamos la clase Estado, en la categoría Workfl ow. Y, dentro de la clase Estado,

el método de clase #defi nición:, el método de instancia #initializeDefi nición: y la variable

de instancia defi nición, de la misma forma que lo hicimos en la clase Proceso.

También implementamos, en la clase Estado, como vemos a continuación:

y ejecutamos los tests. ¡Estamos en verde otra vez!

Al aceptar, creamos la clase Estado, en la categoría Workfl ow. Y, dentro de la clase

nuevaInstancia “Crea una nueva instancia de estado”

^ Estado defi nición: self

defi nición “Responde la defi nición del receptor”

^ defi nición

estado “Responde el estado actual del receptor”

^ estado

Figura 168Figura 168

S

De nada sirve un motor de Workfl ow si no podemos ejecutar código arbitrario en cada

cambio de estado. A su vez, este código será el responsable de decidir qué transición tomar

para pasar de un estado a otro. Para ello, indicamos a la Defi nición de Proceso que utilice un

objeto gestor que le comunique los cambios de estado. Este gestor, además de encargarse

de los cambios de estado, será el que decida qué transición usar para pasar del estado actual

al siguiente.

Bien, vamos a desarrollar el ejemplo más sencillo posible con un gestor que haga avanzar

el proceso desde el estado inicial hasta el estado fi nal.

testLaMasSimpleInstanciaDeProcesoConGestor “Prueba la defi nición más simple posible, con su instancia de proceso y su gestor”

| defi niciónDeProceso proceso gestor estados |

defi niciónDeProceso := Defi niciónDeProceso new. defi niciónDeProceso agregarDefi niciónDeTransición: ‘comenzar y terminar’ desde: ‘principio’ hasta: ‘fi n’.

gestor := GestorConBloque bloque: [:proc | (proc estado nombre = ‘principio’) ifTrue:[‘comenzar y terminar’] ifFalse:[nil] ]. defi niciónDeProceso gestor: gestor.

proceso := defi niciónDeProceso nuevaInstancia. estados := proceso estados.

self should:[estados size = 2]. self should:[estados fi rst defi nición = defi niciónDeProceso estadoInicial]. self should:[estados second defi nición = defi niciónDeProceso estadoFinal]. self should:[estados second transición nombre = ‘comenzar y terminar’].

Con este test estamos defi niendo prácticamente el funcionamiento completo del motor de

Workfl ow. Pero antes de empezar a trabajar en la ejecución del test, vamos a examinar su

contenido para ver cómo va a funcionar el motor. La primera novedad con que nos encon-

tramos es que, a la Defi nición de Proceso, hemos de indicarle cual será su gestor.

Vamos a crear una clase GestorConBloque, que será un Adapter que transforme la interfaz

de un bloque en la interfaz de un Gestor.

Page 94: Libro Smalltalk

186S

ProgramandoconSmalltalk

187S Manos a la obra

El siguiente elemento nuevo es el envío del mensaje #estados (en plural). Este mensaje

tendrá como respuesta una colección con todos los estados incluidos en el proceso, por

lo que es diferente al mensaje #estado (en singular), que usamos anteriormente, que sólo

contesta el estado actual.

Y, por último, tenemos el mensaje #transición, que enviamos a un estado. Este mensaje

responderá qué transición ha sido la responsable de que ese estado se haya convertido en

estado actual.

Al aceptar el método creamos la clase GestorConBloque, en la categoría Workfl ow.

Como siempre, procedemos a ejecutar los tests, acción que nos lleva al rojo.

Patrón de Diseño - Adapter

El patrón Adapter se utiliza para transformar una interfaz en otra, de tal manera

que, una clase que no pueda utilizar la primera, haga uso de ella a través de la

segunda.

ß Problema que soluciona:

Se tiene un componente con cierta funcionalidad que se desea aprovechar, pero que

no se adapta a una determinada interfaz, siendo esto último obligatorio.

ß Implementación:

Crear una nueva clase que será el Adaptador, que extienda del componente existente

e implemente la interfaz obligatoria. De este modo, conseguimos la funcionalidad

que queríamos y cumplimos la condición de implementar la interfaz.

La diferencia entre los patrones Adapter y Facade, es que el primero reutiliza una

interfaz ya existente, mientras que el segundo defi ne una nueva.

Para más información:

– http://es.wikipedia.org/wiki/Adapter_(patrón_de_diseño)

– Libro “Design Patterns - Elements of Reusable Object Oriented Software”.

Implementamos el método GestorConBloque class>>bloque:, en la categoría instance

creation, de la siguiente forma:

y el método GestorConBloque>>initializeBloque:, en la categoría initialization. Segui-

damente, al aceptar el método, creamos la variable de instancia bloque.

Ahora, implementamos el método Defi niciónDeProceso>>gestor:, en la categoría acces-

sing, y generamos la variable de instancia gestor al aceptar el método.

De nuevo, implementamos el método Proceso>>estados, en la categoría accessing:

bloque: aBlockContext “Responde una nueva instancia del receptor” ^ self new initializeBloque: aBlockContext

initializeBloque: aBlockContext “Inicializa el bloque del receptor” bloque := aBlockContext

De nuevo, implementamos el método Proceso>>estados, en la categor accessing

gestor: aGestor “Cambia el gestor del receptor” gestor := aGestor

estados “Responde una colección con todos los estados por los que atravesó el receptor. Primero el más viejo.”

| resultado estadoActual |

resultado := OrderedCollection new.

estadoActual := self estado. [estadoActual isNil] whileFalse: [ resultado add: estadoActual. estadoActual := estadoActual estadoAnterior. ].

^ resultado reversed

Page 95: Libro Smalltalk

188S

ProgramandoconSmalltalk

189S Manos a la obra

y el método Estado>>estadoAnterior, también en la categoría accessing, y creamos la

variable de instancia transición al aceptar.

En este punto, generamos el método Proceso>>cambiarEstado:, en la categoría private.

estadoAnterior “Responde el estado anterior. Si no hay ningún estado anterior, responde nil”

^ transición isNil ifTrue: [nil] ifFalse: [transición desde]

cambiarEstado: aEstado “PRIVADO - Cambia el estado actual del receptor.”

estado := aEstado. self cambioDeEstado.

Métodos privados

Los métodos privados, por convención, se organizan dentro de la categoría private.

Y, del mismo modo, el método #cambioDeEstado, en la categoría private.

cambioDeEstado “PRIVADO - El estado del receptor acaba de cambiar. Notifi car al gestor si existe.”

| nombreDeTransición |

defi nición tieneGestor ifFalse:[^ self].

nombreDeTransición := defi nición gestor estadoCambiadoEn: self. nombreDeTransición isNil ifTrue:[ estado defi nición tieneTransicionesSalientes ifTrue:[self error: ‘Nombre de transición inválida: ‘, nombreDeTransición asString] ]

Ahora, cambiamos el método Proceso>>initializeDefi nición: que es, hasta el momento,

el único lugar donde cambiamos de estado:

e implementamos el método Defi niciónDeProceso>>tieneGestor, en la categoría testing.

Nuevamente, implementamos el método Defi niciónDeProceso>>gestor, en la categoría

accessing.

Seguimos con la creación del método GestorConBloque>>estadoCambiadoEn:, en la

categoría events.

E, igualmente, generamos el método Estado>>nombre, en la categoría accessing.

initializeDefi nición: aDefi niciónDeProceso “Inicializa la defi nición del receptor”

defi nición := aDefi niciónDeProceso.

self cambiarEstado: defi nición estadoInicial nuevaInstancia.

Nuevamente, implementamos el método Defi niciónDeProceso>>gestor, en la categor

tieneGestor “Responde si el receptor tiene un gestor o no” ^ gestor notNil

ifFalse:[ self aplicarTransiciónDeNombre: nombreDeTransición ]

Seguimos con la creación del método GestorConBloque>>estadoCambiadoEn:

gestor “Responde el gestor del receptor” ^ gestor

estadoCambiadoEn: aProceso “Un proceso ha cambiado su estado actual” ^ bloque value: aProceso

nombre “Responde el nombre del receptor” ^ defi nición nombre

Page 96: Libro Smalltalk

190S

ProgramandoconSmalltalk

191S Manos a la obra

A continuación, creamos el método Defi niciónDeEstado>>tieneTransicionesSalientes,

en la categoría testing.

Y, del mismo modo, el método Proceso>>aplicarTransiciónDeNombre:, en la categoría

private.

De nuevo, ejecutamos la misma operación con el método Defi niciónDeProceso>>transición

DeNombre:desde:, en la categoría accessing.

Ahora, el método Defi niciónDeTransición>>nuevaInstanciaDesde:, en la categoría ins-

tancias y creamos la clase Transición, en la categoría Workfl ow, al aceptar el método.

Seguimos con la creación del método Transición class>>defi nición:desde:, en la categoría

instance creation.

Y, del mismo modo, el método Proceso>>aplicarTransiciónDeNombre:, en la categor

tieneTransicionesSalientes “Responde si el receptor tiene o no transiciones salientes” ^ transicionesSalientes notEmpty

aplicarTransiciónDeNombre: aString “PRIVADO - Aplica la transición de nombre dado”

| defi niciónDeTransición transición |

defi niciónDeTransición := defi nición transiciónDeNombre: aString desde: estado.

transición := defi niciónDeTransición nuevaInstanciaDesde: estado.

self cambiarEstado: transición hasta

transiciónDeNombre: aString desde: anEstado “Responde una transición de nombre dado y que sea saliente del estado dado”

^ transiciones detect:[:each | each nombre = aString and:[each desde = anEstado defi nición]]

Seguimos con la creación del método Transición class>>defi nición:desde:, en la categor

nuevaInstanciaDesde: anEstado “Crea una nueva instancia de transición” ^ Transición defi nición: self desde: anEstado

Y del método Transición>>initializeDefi nición:desde:, en la categoría initialization.

Después, creamos las variables de instancia defi nición, desde y hasta al aceptar el método.

El siguiente paso es la creación del método Defi niciónDeEstado>>nuevaInstancia

Transición:, en la categoría instancias.

Y, a continuación, generamos el método Estado class>>defi nición:transición:, en la cate-

goría instance creation.

Del mismo modo, el método Estado>>initializeDefi nición:transición:, en la categoría

initialization.

defi nición: aDefi niciónDeTransición desde: anEstado “Crea una nueva instancia del receptor” ^ self new initializeDefi nición: aDefi niciónDeTransición desde: anEstado

El siguiente paso es la creación del método Defi niciónDeEstado>>nuevaInstancia

initializeDefi nición: aDefi niciónDeTransición desde: anEstado “Inicializa el receptor”

defi nición := aDefi niciónDeTransición. desde := anEstado. hasta := defi nición hasta nuevaInstanciaTransición: self.

Y, a continuación, generamos el método Estado class>>defi nición:transición:, en la cate-

nuevaInstanciaTransición: aTransición “Crea una nueva instancia de estado”

^ Estado defi nición: self transición: aTransición

Del mismo modo, el método Estado>>initializeDefi nición:transición:, en la categor

defi nición: aDefi niciónDeEstado transición: aTransición “Crea una nueva instancia del receptor”

^ self new initializeDefi nición: aDefi niciónDeEstado transición: aTransición

initializeDefi nición: aDefi niciónDeEstado transición: aTransición “Inicializa la defi nición y la transición del receptor”

defi nición := aDefi niciónDeEstado. transición := aTransición

Page 97: Libro Smalltalk

192S

ProgramandoconSmalltalk

193S Manos a la obra

Ahora, implementamos los métodos Transición>>hasta, Transición>>desde,

Estado>>transición y Transición>>nombre, en la categoría accessing.

nombre “Responde el nombre del receptor” ^ defi nición nombre

transición “Responde la transición que dio origen al receptor” ^ transición

desde “Responde el estado ‘desde’ del receptor” ^ desde

hasta “Responde el estado ‘hasta’ del receptor” ^ hasta

Bien, lo primero que nos encontramos es algo que ya habíamos previsto al comenzar. Tene-

mos dos tipos de objetos: las Defi niciones y las Instancias. Si prestamos atención, observamos

que todas las instancias (Proceso, Estado y Transición) comparten aspectos comunes, lo que

suele indicar que la jerarquía de clases no es correcta. Lo que está ocurriendo es que cono-

cemos todos los Procesos, Estados y Transiciones, pero no volcamos ese conocimiento en el

entorno. Para hacerlo, vamos a crear una nueva clase llamada Instancia (ver Figura 170).

Figura 170Figura 170

S

Después de tanto trabajo, ejecutamos los tests y ¡estamos en verde!

Llegados a este punto del ejemplo, hemos de limpiar el código, tal y como hicimos para el

último test, por lo que, según nuestro autor, nos espera un buen trabajo de limpieza.

Figura 173Figura 173

S

A continuación, modifi camos las clases Proceso, Estado y Transición para que ahora sean

subclases de Instancia (en lugar de ser subclases de Object). Para modifi car la superclase

usamos el Browser de Clases y, en la defi nición de la clase (vemos la defi nición cuando

tenemos seleccionada la Clase, pero no tenemos seleccionados ni Categoría de Métodos ni

Métodos), reemplazamos Object por Instancia, tal como indican las Figuras 171 y 172, y

aceptamos.

Figuras 171 - 172Figuras 171 - 172

S

Figuras 171 - 172

SRepetimos el mismo proceso para las clases Proceso y Transición.

Ahora, seleccionamos la clase Instancia, en el Browser, y presionamos el botón hier (hie-

rarchy – jerarquía), abriéndose el Browser Jerárquico (ver Figura 173).

Page 98: Libro Smalltalk

194S

ProgramandoconSmalltalk

195S Manos a la obra

Figura 174Figura 174

S

Con este Browser confi rmamos, visualmente, que hemos ejecutado los cambios de super-

clase para las tres clases.

Entre los aspectos comunes a las tres clases encontramos la variable de instancia defi -

nición. Ahora, usamos otra funcionalidad del Refactoring Browser para subir la variable

desde las subclases a la clase Instancia. Seleccionamos la clase Instancia, pedimos el menú

contextual y seleccionamos la opción pull up... del submenú instance variables.

Browser Jerárquico

El Browser Jerárquico ofrece un formato diferente a la hora de presentar las clases. En

lugar de presentar dos paneles con las Categorías de Clases y las Clases, este Browser

muestra sólo un panel con un árbol que indica la relación superclase-subclase.

Figura 175Figura 175

SSeguidamente, seleccionamos una de las variables defi nición (ver Figura 175):

Buscamos el método Estado>>initializeDefi n

ición: y, desde el menú contextual del método,

seleccionamos la opción push up, tal y como

nos indica la Figura 176.

Figura 176Figura 176

SA continuación, repetimos la operación para el método Estado>>nombre y confi rmamos

con yes cuando el Refactoring Browser nos pregunta Do you want to remove duplicate sub-

class methods? (¿Quiere remover los métodos duplicados en las subclases?). Al contestar

afi rmativamente esta pregunta, el Refactoring Browser borrará cualquier implementación

similar a la subida a la clase Instancia en sus subclases.

Volvemos a ejecutar la misma operación para el método Estado>>defi nición. Y, de nuevo,

hacemos lo mismo para el método Estado class>>defi nición:, contestando afi rmativa-

mente a la pregunta de remover métodos duplicados.

S

Page 99: Libro Smalltalk

196S

ProgramandoconSmalltalk

197S Manos a la obra

Ahora, cambiamos el método Proceso>>initializeDefi nición: de la siguiente forma:

y modifi camos el constructor Estado class>>defi nición:transición:.

initializeDefi nición: aDefi niciónDeProceso “Inicializa la defi nición del receptor”

super initializeDefi nición: aDefi niciónDeProceso.

self cambiarEstado: defi nición estadoInicial nuevaInstancia.

Procedemos a borrar el método Estado>>initializeDefi nición:transición: y, de nuevo,

modifi camos el constructor Transición class>>defi nición:desde:

defi nición: aDefi niciónDeEstado transición: aTransición “Crea una nueva instancia del receptor”

^ (self defi nición: aDefi niciónDeEstado) initializeTransición: aTransición

initializeTransición: aTransición “Inicializa la transición del receptor”

transición := aTransición

Usar el fuente de un método para crear otro método parecido

Cuando necesitamos crear un método similar a uno ya existente, podemos

modifi car el método antiguo a modo de plantilla, simplemente cambiando su

nombre y aceptando después.

Al realizar esta operación, el Browser crea otro método y deja el anterior intacto.

En este punto, creamos el método Estado>>initializeTransición:, en la categoría initia-

lization.

A continuación, creamos el método Transición>>initializeDesde:

defi nición: aDefi niciónDeTransición desde: anEstado “Crea una nueva instancia del receptor”

^ (self defi nición: aDefi niciónDeTransición) initializeDesde: anEstado

initializeDesde: anEstado “Inicializa el ‘desde’ del receptor”

desde := anEstado

Y, lo mismo, con el método Transición>>initializeDefi nición:

Después, borramos el método Transición>>initializeDefi nición:desde:

Finalmente, ejecutamos todos los tests y vemos que seguimos en verde. Bien, sigamos lim-

piando.

Las dos especializaciones del método Instancia>>initializeDefi nición: (en las clases Pro-

ceso y Transición) son para llevar a cabo alguna operación con la defi nición cuando la

instancia la reconoce. Así, modifi camos el método Instancia>>initializeDefi nición: de la

siguiente forma:

initializeDefi nición: aDefi niciónDeTransición “Inicializa la defi nición del receptor”

super initializeDefi nición: aDefi niciónDeTransición.

hasta := defi nición hasta nuevaInstanciaTransición: self.

initializeDefi nición: aDefi niciónDeEstado “Inicializa la defi nición del receptor”

defi nición := aDefi niciónDeEstado.

self defi niciónCambiada.

Page 100: Libro Smalltalk

198S

ProgramandoconSmalltalk

199S Manos a la obra

e implementamos el método Instancia>>defi niciónCambiada con la siguiente instrucción:

Ahora, usando la función Extract Method extraemos las expresiones que están inmediatamente

después de la llamada a super, hacia nuevos métodos de nombre #defi niciónCambiada.

defi niciónCambiada “La defi nición ha cambiado en el receptor”

Y borramos los métodos Proceso>>initializeDefi nición: y Transición>>initialize-

Defi nición:

De nuevo, ejecutamos los tests y seguimos en verde.

En este momento, nos tocaría refactorizar la jerarquía de Defi nición. De este modo,

crearíamos una clase de nombre Defi nición, modifi caríamos las superclases de

Defi niciónDeProceso, Defi niciónDeEstado y Defi niciónDeTransición, subiríamos la

variable de instancia nombre, los métodos de instancia #nombre y #initializeNombre:,

el método de clase #nombre, etc. Al crear la jerarquía nos hubiésemos dado cuenta que

nos olvidamos de ponerle nombre a la Defi niciónDeProceso y, al colgarla de la clase

Defi nición, la heredaría.

Así pues, dejamos al lector la tarea de completar la factorización de la jerarquía

Defi nición.

El último paso que nos queda por dar es la creación de la clase Gestor y convertir el

GestorConBloque en una subclase. Para ello, creamos la clase e implementamos el método

#estadoCambiadoEn:

defi niciónCambiada “La defi nición ha cambiado en el receptor”

hasta := defi nición hasta nuevaInstanciaTransición: self

defi niciónCambiada “La defi nición ha cambiado en el receptor”

self cambiarEstado: defi nición estadoInicial nuevaInstancia

estadoCambiadoEn: aProceso “Un proceso ha cambiado su estado actual.

Hace lo que se necesite por el cambio de estado, luego se responde el nombre de la transición a tomar para pasar al próximo estado, o nil cuando el estado sea el fi nal”

^ self subclassResponsibility

Mensaje #subclassResponsibility

El mensaje #subclassResponsibility es la forma de indicar que ese método debe ser

implementado en las subclases. Es la forma de marcar un método como abstracto.

Con esto damos por concluido el ejemplo del motor de Workfl ow. Se puede descargar el

código completo del ejemplo desde el sitio web del libro (http://smalltalk.consultar.com)

aunque lo que, realmente, recomienda nuestro autor es que se realice el ejemplo, paso a

paso, siguiendo las instrucciones del libro.

Page 101: Libro Smalltalk

201S La Yapa

YAPACAPÍTULO 4CAPÍTULO 4 LA

YAPA: Sust. Regalo que el vendedor hace al comprador. (De....): además, por añadidura.

En este capítulo hablaremos, sólo superfi cialmente, de algunas funcionalidades y caracterís-

ticas que Smalltalk posee pero que, por el enfoque y el tamaño del libro, no seremos capaces

de desarrollar en su plenitud. Nuestro autor no oculta que el objetivo principal de este capí-

tulo es despertar la curiosidad de los lectores y que, esa curiosidad, sirva de motor para que

continúen en el proceso de aprender Smalltalk.

4.1 Mensaje #become:

El mensaje #become:, presente en prácticamente todos los dialectos, permite intercam-

biar un objeto (el receptor) por otro (el argumento) en toda la imagen. Los objetos que

hacían referencia al receptor, después del envío del mensajes, harán referencia al objeto

dado como argumento.

Este mensaje es muy poderoso y, a su vez, peligroso. Como sucede con todas las herra-

mientas poderosas, existen algunos casos donde su uso es la mejor solución, pero hay

4.1

Page 102: Libro Smalltalk

202S

ProgramandoconSmalltalk

203S La Yapa

muchos más casos en los que su uso sería un error.

Uno de los casos donde suele utilizarse con éxito es cuando queremos reemplazar una

instancia “falsa” por la real; es frecuente tener que entregar instancias incompletas o,

simplemente, entregar un falso objeto que, al usarse, instancie el objeto real y se inter-

cambie por él (un lazy-instantiation).

4.2 Mensaje #doesNotUnderstand:

Cuando el receptor no entiende un mensaje, la máquina virtual le da otra oportunidad

para reaccionar enviándole el mensaje #doesNotUnderstand: con un objeto de clase

Message como argumento, donde se almacena toda la información del mensaje fallido.

Al igual que en el caso anterior, el mensaje #doesNotUnderstand: es, a la vez, poderoso y

peligroso. Y, también, como en el caso anterior, existen algunos casos donde su uso es la

mejor opción. Tal vez, el ejemplo más representativo es el de hacer proxies que deleguen

todos los mensajes que reciben a un objeto que conozcan. Combinado con el mensaje

anterior, se puede hacer que en el primer mensaje no entendido por el proxy, éste instan-

cie (o localice) el objeto real y se intercambie con el usando el #become:.

4.3 Mensajes #perform:, #perform:with:, #perform:withAll:, etc.

Estos mensajes permiten enviar un mensaje por nombre. El SUnit, por ejemplo, lo utili-

za para enviar al objeto de clase TestCase un mensaje por cada uno de los métodos que

comienzan por #test.

4.4 Pseudo-variable thisContext

La pseudo-variable thisContext permite acceder al objeto que representa el contexto de

activación del método. Con esta variable se puede acceder, entre otros, a los valores de las

variables locales, al emisor del mensaje, etc. El Depurador hace un uso intensivo de esta

pseudo- variable, al igual que el Seaside la utiliza para crear los continuations.

4.5 SLang, máquina virtual y plugins

El SLang es un subconjunto de la sintaxis y funcionalidad del lenguaje Smalltalk, que

permite generar código en lenguaje C con la misma funcionalidad. La máquina virtual

está escrita en SLang.

Esta funcionalidad también permite escribir plugins, que son fragmentos de código

Smalltalk que, al convertirlos a C y compilarlos, se ejecutan a mayor velocidad. El SLang,

al ser un subconjunto, permite que la depuración se haga con la ricas herramientas de

Smalltalk.

4.6 FFI – Foreign Function Interface

El FFI es un conjunto de objetos que permiten llamar a funciones que residen en libre-

rías compartidas. Por ejemplo, el paquete ODBC hace uso intensivo de esta funcionali-

dad para acceder a las funciones de la DLL (o el .so de Linux) de ODBC.

4.7 Metaprogramación

En Smalltalk las clases son objetos y se las puede manipular como se hace con cualquier

objeto: enviando mensaje.

Disponemos de mensajes para indagar sobre qué métodos tiene la clase, para conocer

sus superclases, para ver todas las instancias, etc. Pero también podemos cambiar la es-

tructura de las clases usando mensajes, lo que quiere decir, entre otras cosas, que pode-

mos generar programas que, a su vez, creen programas (metaprogramas).

4.8 Multithreading

Smalltalk permite la programación con procesos (el nombre que Smalltalk le da a sus

threads) desde sus primeras versiones. Contamos con objetos para sincronizar el trabajo

entre diferentes procesos como semáforos, colecciones thread-safe, etc.

4.2

4.3

4.4

4.7

4.8

4.6

4.5

Figura 1

203SS La Yapa

Figura 1

S

Page 103: Libro Smalltalk

204S

ProgramandoconSmalltalk

205S La Yapa

Figura 5Figura 5

S

Figura 4Figura 4

S

4.9 SqueakMap

SqueakMap es un repositorio de proyectos Squeak. A día de hoy, se pueden descargar e

instalar más de 600 aplicaciones.

Figura 3Figura 3

S

4.9

4.10 MVC

MVC es el nombre que recibe el tradicional framework para hacer aplicaciones gráfi cas

que incluía el Smalltalk/80. Ese framework recibe el mismo nombre que el patrón de

diseño ya que es parte fundamental de su arquitectura. Se trata de es un framework muy

liviano que puede ser utilizado para el desarrollo de aplicaciones donde el consumo de

memoria sea una limitación.

4.10

Figura 2

4.10 MVC 4.10

Figura 2

S

4.11 Morphic

En Squeak existe otro framework para la construcciones de interfaces gráfi cas de usua-

rio. Morphic permite una manipulación más concreta de los objetos representados en

la pantalla. Los conceptos básicos de Morphic derivan del proyecto Self (http://research.

sun.com/self/).

4.11

4.12 Algunos proyectos con Squeak

A continuación mostramos algunos proyectos bastante ilustrativos de lo que se puede

diseñar en Squeak.

4.12

VideoFlow, procesamiento de vídeo.

Page 104: Libro Smalltalk

206S

ProgramandoconSmalltalk

207S

SMALLTALKCAPÍTULO 5CAPÍTULO 5 EL FUTURO DE

El futuro próximo de Smalltalk es servir como herramienta para generar el entorno de

desarrollo que vuelva obsoleto al mismo Smalltalk. Se trata de un objetivo ambicioso, y

cuyo desarrollo ya se está llevando a cabo en diferentes áreas.

A continuación, enumeramos algunos de los proyectos que se están ejecutando en la

actualidad, y de los que se puede obtener más informaciónen los enlaces de referencia.

Traits

Smalltalk, desde los inicios, optó por un sistema de reutilización basado en herencia simple

para, sobre todo, evitar las complicaciones que conlleva un sistema de herencia múltiple

como, por ejemplo, el de C++.

Traits es un proyecto para ampliar el poder de expresión de un sistema de herencia simple,

pero sin caer en las complicaciones de un sistema de herencia múltiple. Probablemente, la

próxima versión de Squeak, la 3.9, incluirá una primera versión para entornos de producción.

Figura 6 - 7Figura 6 - 7

SProyecto Magrathea.

Figura 8 - 9 - 10Figura 8 - 9 - 10

S

Proyecto E-Alterego.

Control de Robots.

Procesamiento

fotográfi co.

Leyendo un GPS.

Page 105: Libro Smalltalk

ProgramandoconSmalltalk

208S El Futuro de Smalltalk209S

Para más información: http://www.iam.unibe.ch/~scg/Research/Traits/

Tweak

El proyecto Smalltalk fue, desde el principio, uno de los motores que empujó el diseño

de interfaces de usuario. Tweak es un nuevo framework que pretende trasladar la sencillez

de la programación tipo eToys a un entorno con la potencia completa de Smalltalk.

Para más información: http://tweak.impara.de/

64 bits

Las primeras máquinas virtuales de Smalltalk eran de 16 bits y permitían un limitadísimo

direccionamiento de objetos. La primera implementación de Squeak ya era de 32 bits,

aumentando tremendamente la capacidad de direccionamiento. Sin embargo, para que

Smalltalk siga liderando la evolución de los entornos de programación, es necesario

pasar a una arquitectura de objetos de 64 bits.

Para más información: http://www.squeakvm.org/squeak64/

OpenCroquet

¿Qué pasaría si desarrollásemos un sistema operativo, hoy en día, teniendo todos los

conocimientos que ya se tienen? Ésta es la pregunta que rige el desarrollo de OpenCroquet,

un sistema de objetos distribuido, 100% colaborativo, con una rica interfaz de usuario

de objetos 3D (ver Figuras 177, 178 y 179).

Para más información: http://www.opencroquet.org

Tweak

64 bits

Diferentes capturas del proyecto OpenCroquet Diferentes capturas del proyecto OpenCroquet

Figura 177Figura 177

S Figura 178

Page 106: Libro Smalltalk

ProgramandoconSmalltalk

210S 211S

Figura 179Figura 179

S

Cómo continuar

Sin duda, lo más importante para aprender Smalltalk es meter mano en un Smalltalk.

No vale de nada leer cientos de libros si no nos metemos de lleno en un ambiente de

Smalltalk y comenzamos a hacer cosas.

Pero también es cierto que la experiencia puede ser más fácil si logramos percibir algo de

la fi losofía del desarrollo con Smalltalk desde algunos libros. A nuestro autor, particular-

mente, le impactaron, de manera especial, las siguientes lecturas:

Libros

ß Smalltalk-80 - The Language: en este libro se puede entender, de personas que pati-

ciparon en el desarrollo de Smalltalk, la fi losofía del lenguaje y las motivaciones que lo

hicieron posible.

ß Smalltalk-80 - Bits of History, Words of Advice: este libro le impactó por lo actual de

los comentarios hechos por personas que probaron Smalltalk a principios de los años 80.

ß Smalltalk Best Practice Patterns: esta obra le enseñó que una de las cosas más im-

portantes, para ser un buen programador Smalltalk, es prestar muchísima atención a la

claridad del código.

ß Smalltalk with Style: éste le mostró la mayoría de las convenciones que se utilizan a la

hora de escribir código Smalltalk.

ß Design Patterns - Elements of Reusable Object Oriented Software: no es posible

decir hoy en día que se sabe programar con objetos si no se ha leído este libro. Éste es

el culpable de que hoy nuestro autor esté escribiendo un libro de Smalltalk y no uno de

Page 107: Libro Smalltalk

212S 213S

Conclusión

Este libro no pretendía ser un manual de Smalltalk, ni tampoco una guía de referencia,

como indicamos en la Introducción. El objetivo del autor al escribir esta obra ha sido

el de mostrar la fi losofía inherente a Smalltalk, la manera en que ésta impacta en el de-

sarrollo de software y, a su vez, cómo esta forma de trabajar genera software de mayor

calidad en menos tiempo que con otras herramientas.

En palabras de nuestro autor: “elegí mostrar cómo un ambiente del poder de Smalltalk per-

mite un estilo de programación muy incremental, ya que el costo de los cambios es muy bajo.

Sin embargo, creo que es necesario aclarar que Smalltalk no requiere que se trabaje así, y que

es perfectamente posible utilizar un ambiente de Smalltalk con una forma de trabajo menos

incremental y menos dinámica. Cada programador tiene que decidir, entre otras cosas, qué

tipo de programación prefi ere. En este libro sólo intenté mostrar el tipo de programación que

yo prefi ero, y que no puedo desarrollar en otras herramientas que no sean Smalltalk”.

“Es posible que en algún lector quede la idea de que esta metodología no es muy rápida. Si

eso les ha ocurrido consideren que tuve que mostrar, paso a paso, las herramientas y cómo

se usan, también tuve que introducir notas con explicaciones sobre tal o cual clase, y eso

podría haber impactado negativamente en la percepción del tiempo de desarrollo. Reto a

cualquiera que se haya podido quedar con ese sabor de boca a probar la metodología en

algún sistema real y que extraigan las conclusiones sólo después de esa experiencia”.

Por todo esto, Smalltalk es una pieza increíble de software, no obstante, no es la meta en sí

mismo, sino que es parte de una visión sobre cómo deberíamos hacer uso de los ordenadores.

Los objetivos planteados en las ideas que rigen el desarrollo de Smalltalk todavía no han

sido alcanzados en su plenitud. Sin embargo, Smalltalk sí que nos permite, en la actuali-

dad, imaginar cómo podría ser la experiencia de utilizar un ordenador y, para alcanzar

Java o .NET. A través de las explicaciones de algunos patrones, se enteró de la existencia

de Smalltalk y de su impacto sobre la tecnología de objetos. Éste es el libro que despertó

su curiosidad por aprender Smalltalk.

ß The Dessign Patterns Smalltalk Companion: esta obra le enseñó mucho Smalltalk

por comparación con la implementación de los patrones en el libro anterior.

Papers o artículos

ß Design Principles Behind Smalltalk: excelente descripción de las motivaciones que

rigen el desarrollo del proyecto Smalltalk. Parece ciencia fi cción si consideramos que la

nota fue publicada en la revista Byte de agosto de 1981.

ß Personal Dynamic Media: excelente explicación de las motivaciones que subyacen del

desarrollo de Smalltalk, escrita por Alan Kay en el año 1976.

ß The Early History of Smalltalk: ésta es una historia de Smalltalk, escrita por Alan

Kay, en el año 1993 (antes de que comenzara el proyecto Squeak, allá por el 1995) en la

que cuenta de dónde vienen las ideas principales. Termina con una frase que también le

marcó especialmente: “¿Dónde están los Dan (Ingalls) y las Adele (Goldberg) de los 80s y

los 90s que nos lleven al próximo nivel de desarrollo?”.

Grupos de Usuarios

Existen diferentes grupos de usuarios y listas de distribución en Internet. Las comunida-

des de usuarios de Smalltalk suelen ser muy amables, a diferencia de otras comunidades,

contestando a preguntas de personas que acaban de introducirse en el ambiente.

Papers o artículos

Grupos de Usuarios

Page 108: Libro Smalltalk

214S

ProgramandoconSmalltalk

el objetivo máximo (que cualquier persona, y no sólo programadores, pueda interactuar

con la información y construir conocimiento a través de esa interacción) debemos seguir

mejorando este entorno.

Por ello, los programadores tienen una tarea muy clara: trabajar para convertirse en mejo-

res programadores y compartir con todo el mundo - programadores y no programadores

– los conocimientos que van adquiriendo en el día a día.

APÉNDICE

Page 109: Libro Smalltalk

217SS

Herramientas usadas en el libro

Para mostrar la forma de trabajo que permite el uso de un entorno de objetos como

Smalltalk, en este manual, el autor ha elegido desarrollar algunas aplicaciones de ejemplo

paso a paso, confi ando en que el lector perciba la diferencia entre trabajar con Smalltalk

y una experiencia de primera mano. El sentido de esta obra se perdería si el autor no ha

conseguido que los lectores se animen a probar, en un entorno de Smalltalk, todo lo que

les venga en gana.

Para reducir al mínimo el tiempo necesario para entrar en el ambiente, el autor creó una

imagen de Squeak pre-confi gurada y con algunos paquetes extras instalados.

La imagen utilizada es una 3.8-full ofi cial con varias preferencias cambiadas y con los

siguientes paquetes instalados:

NOMBRE VERSIÓN DESCRIPCIÓN

YAXO 2.2 Parser de XML.

XML Stack Parser 1 Parser de XML basado en una pila.

Copy as HTML 1 Utilidad para copiar al porta papeles una

versión HTML del texto Squeak. Incluye el

formato con sus colores, etc. Usado para el

código mostrado en este libro.

StringEnh 1 Algunos extras para la clase String.

Page 110: Libro Smalltalk

218S 219S

S

NOMBRE VERSIÓN DESCRIPCIÓN

Shout 4 Paquete que muestra sintax-highlight

mientras se escribe.

ShoutMonticello 2 Extensiones Shout para las herramientas

relacionadas con el Monticello.

ShoutWorkspace 2 Un Workspace que, valiéndose del Shout,

hace sintax-highlight mientras se escribe.

Refactoring Browser

for 3.8

3.8.43 Extensiones para los browsers para hacer

refactorizaciones del código.

SUnit 3.1.22 Framework para hacer UnitTesting con

Smalltalk. Derivado directo del primer

framework de UnitTesting escrito por Kent

Beck.

DynamicBindings 1.2 Framework para hacer UnitTesting con

Smalltalk. Derivado directo del primer

framework de UnitTesting escrito por Kent

Beck.

KomServices 1.1.1 Paquete requerido por KomHttpServer.

KomHttpServer 7.0.2 Paquete requerido por Seaside. Servidor web

íntegramente desarrollado en Smalltalk.

Seaside 2.5 Framework de desarrollo de aplicaciones

web basado en continuations. Para más

información ver el sitio www.seaside.st

La imagen ofi cial se puede descargar desde www.squeak.org, concretamente de http://ftp.

squeak.org/current_stable/Squeak3.8-6665-full.zip.

Para construir una imagen, como la utilizada en este manual, lo más fácil es instalar el

paquete ProgramacionConSmalltalk, usando el SqueakMap, y éste instalará, a su vez, las

herramientas necesarias descargándolas desde Internet.

Page 111: Libro Smalltalk

221S

Bibliografía

Este manual, como ya adelantamos en la Introducción, no es una guía completa de Sma-

lltalk. Por ello, recomendamos al lector que consulte los siguientes libros y documentos

como complemento ideal para continuar aprendiendo Smalltalk.

Algunas de estas referencias se pueden descargar, de forma gratuita, desde:

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

A Little Smalltalk

Budd, Tim

Addison Wesley. 1987.

Back to the future - The Story of Squeak, A Practical Smalltalk Written in Itself

Kay, Alan

http://users.ipa.net/~dwighth/squeak/oopsla_squeak.html

OOPSLA 97 Proceeding. P. 318-326. ACM Press, New York, 1997.

(a postscript by Dan Ingalls in [Guzdial/Rose 2001]).

Design Patterns - Elements of Reusable Object Oriented Software

Gamma, E., R. Helm, R. Johnson, and J. Vlissides

Addison Wesley. 1995.

Design Principles Behind Smalltalk

Ingalls, Dan

http://users.ipa.net/~dwighth/smalltalk/byte_aug81/design_principles_behind_smalltalk.html

Page 112: Libro Smalltalk

222S 223S

eXtreme Programming eXplained - Embrace Change

Beck, Kent

Addison Wesley. 1999.

Guide to Better Smalltalk. A Sorted Collection

Beck, Kent

Cambridge University Press en asociación con SIGS Books. United State of America. 1999.

Inside Smalltalk (vol. one and two)

LaLonde, Wilf. R. Pugh, John. R.

Prentice Hall. 1990.

Object-Oriented Implementation of Numerical Methods. An Introduction with

Java and Smalltalk

Besset, Didier H.

Morgan Kaufmann Publishers. United State of America. 2001.

Personal Dynamic Media

Kay, Alan. Goldberg, Adele

http://www.dolphinharbor.org/dh/smalltalk/documents/

Reprinted in The New Reader. 1976.

Powerful Ideas in the Classroom

B. J. Allen Conn. Rose, Kim

Viewpoints Research Institute, Inc. 2003.

Refactoring Browser Tool

Brant, Hohn, and Don Robert.

http://st-www.cs.uiuc.edu/~droberts/tapos/TAPOS.htm

Refactoring. Improving The Design of Existing Code

Fowler, Martin

Addison Wesley. Massachusetts. 1999.

Simple Smalltalk Testing - With Patterns

Beck, Kent

http:/7www.xprogramming.com/testfram.htm

Smalltalk An Introduction To Aplication Development Using visualwork

Hopkins, Trevor and Horan, Bernard

Pearson Education. 1995.

Smalltalk and Object Orientation - An Introduction

Hunt, John.

Springer-Verlag. 1997.

Smalltalk Best Practice Patterns

Beck, Kent

Pretice Hall, New Jersey. 1997.

Smalltalk by Example - The Developer’s Guide

Sharp, Alex

McGraw Hill Text. 1997.

Smalltalk with Style

Skublics, Suzanne. Klimas, Edward J. Thomas, David A.

Pretice Hall. New Jersey. 1996.

Smalltalk-80 - The Language

Goldberg, Adele. Robson, David

Addison-Wesley Proffesional. 1989.

Smalltalk-80 - Bits of History, Words of Advice

Krasner, Glenn

Addison Wesley. California. 1983.

Smalltalk-80 - The Interactive Programming Enviroment

Goldberg, Adele

Addison Wesley. California. 1984.

Smalltalk-80 - The Language and Its Implementation

Goldberg, Adele. Robson, David

Addison Wesley. California. 1983.

Page 113: Libro Smalltalk

224S 225S

Smalltalk, Object and Design

Chamond, Liu

To Excel. New York. 1996.

Squeak - Object-Oriented Design whit Multimedia Applications

Guzdial, Mark

Prentice Hall. New Jersey. 2001.

Squeak. Open Personal Computing and Multimedia

Guzdial, Mark. Rose, Kim

Prentice Hall. New Jersey. 2002.

Test-Driven Development - By Example

Beck, Kent

Adisson Wesley. 2002.

The Art and Science of Smalltalk

Lewis, Simon

Prentice-Hall. 1995-1999.

The Dessign Patterns Smalltalk Companion

Alpert, Sherman. Brown, Kyle. Woolf, Bobby

Addison Wesley. California. 1998.

The Early History of Smalltalk

Kay, Alan

http://gagne.homedns.org/~tgagne/contrib/EarlyHistoryST.html

The Joy of Smalltalk

Tomek, Ivan. 2000.

The Taste of Smalltalk

Kaehler, Ted. Patterson, Dave

WW Norton & Co. 1986.

Tools For Thought. The History and Future of Mind-Expanding Technology

Rheingold, Howard

The MIT Press Cambridge, Massachusetts. 2000.

http://www.rheingold.com/texts/tft/

Una Explicación de la Programación Extrema - Aceptar el cambio

Beck, Kent

Adisson-Wesley Iberoamericana España, S.A. Madrid. 2002.

Page 114: Libro Smalltalk