En esta clase vamos a ver un enfoque bastante radical o diferente a los que veníamos viendo para la construcción de aplicaciones web. Para eso vamos a cambiar muchas cosas:
Empecemos entonces por hacernos amigos de la tecnología de a poquito
Existen muchos IDEs para trabajar con Smalltalk
Nosotros nos quedamos con Pharo, porque es el IDE que más actividad académica y comercial tiene: es un software open-source que está en continuo movimiento.
El entorno de trabajo de Smalltalk es diferente de lo que estamos acostumbrados:
Smalltalk es un lenguaje muy sencillo de aprender. Sólo existen estas construcciones:
objeto mensajeUnario
objeto mensajeBinario parametro
objeto mensajeDePalabraClave: parametro1
objeto mensajeDeUnParametro: parametro1 conOtroParametro: parametro2 (también es de palabra clave)
Es decir que cuando tengo que enviar un mensaje con muchos parámetros los voy separando con un prefijo que construye el nombre del método
mensajeDeUnParametro:conOtroParametro:
es el nombre del método (o selector para los smalltalkeros)
Abrimos un workspace y probamos algunas cosas:
3 + 5
con el botón derecho hacemos Print It y eso nos devuelve por suerte... 8. Enviamos un mensaje binario al objeto 3.
Print It implica que lo que devuelve un mensaje no tiene efecto colateral, lo que nos importa es ver qué devuelve.
Do It por el contrario no muestra lo que devuelve un mensaje, porque lo importante es afectar al objeto al que le enviamos el mensaje.
Seguimos jugando con números:
9 sqrt
Esto envía al objeto 9 el mensaje sqrt (square root, raíz cuadrada). Para ver cómo resuelve un mensaje, podemos entrar en la clase SmallInteger, o bien hacer desde el mismo workspace:
9 browse
Esto nos deja parados en el System Browser en la clase del objeto receptor.
Enviamos un mensaje de palabra clave:
9 radix: 2
Y eso pasa el número 9 a un String que representa el número en base 2.
Si vemos cómo se implementa un método, entenderemos que Smalltalk es bastante simple en su sintaxis:
sumaleDosA: unNumero
" en el comentario ponemos lo que hace un método "
| variableLocal |
variableLocal := 2 + unNumero.
^variableLocal
Y eso es todo.
Decisiones que tomaron quienes desarrollaron el Smalltalk:
En Smalltalk tenemos la clase abstracta Boolean, de la cual heredan las subclases True y False.
true es el literal asociado al único objeto de la clase True, al igual que false que se asocia al único objeto en la imagen para la clase False.
¿Qué podemos hacer con un boolean?
Podemos enviar un mensaje unario, para obtener el contrario:
false not
Lo cual devuelve true. También podemos evaluar dos booleanos, con and/or:
false & true
true | false
Lo cual devuelve false y true respectivamente.
Si queremos ver la implementación de estos métodos: vamos al System Browser, botón derecho Find class (f): Boolean
Por otra parte, existen los objetos bloque, que permiten definir comportamiento:
programitaFactorial5 := [ 5 factorial ]
Esta vez hago botón derecho > DoIt, porque no me interesa mucho qué devuelve [ 5 factorial ], lo que me interesa es que la referencia a programitaFactorial5 apunte hacia ese objeto bloque.
¿Cómo puedo evaluar el bloque?
Enviando un mensaje, claro:
programitaFactorial5 value
Esto produce un resultado que quiero ver, entonces uso Print It: recibo un 120. Todo bien.
¿No se podrá dejar el 5 como parámetro? Sí, construyendo otro objeto bloque:
programitaFactorial := [ :numero | numero factorial ]
Pero ahora no puedo enviar el mensaje value, intentemos por las dudas:
programitaFactorial value.
Nos da error: 'This block accepts 1 argument, but was called with 0 arguments.'
Pero sí puedo hacer:
programitaFactorial value: 6.
Que da, como todos sabemos 720.
Ahora volvamos a Boolean, hay un mensaje de palabra clave ifTrue: ifFalse: que entienden tanto true como false, y que permite resolver un if.
Supongan que tenemos una condición booleana que no sabemos a priori si se puede cumplir o no. ¿Podríamos tratar a False y a True como objetos polimórficos, mandándole dos códigos:
Entonces,
(3 > 7) ifTrue: [ 'hola' ] ifFalse: [ 'chau' ]
(8 < 17) ifTrue: [ 'hola' ] ifFalse: [ 'chau' ]
Si los objetos true y false son polimórficos, entonces esto es bastante fácil de lograr:
El método ifTrue:ifFalse: en True evalúa el primer bloque (alternativa por true) y descarta el segundo.
ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock
^trueAlternativeBlock value
El método ifTrue:ifFalse: en False evalúa el segundo bloque (alternativa por false) y descarta el primer bloque.
ifTrue: trueAlternativeBlock ifFalse: falseAlternativeBlock
^falseAlternativeBlock value
Tener objetos bloque es una abstracción muy interesante:
nombres := OrderedCollection with: 'Dalila' with: 'Paula' with: 'Joe'.
nombres select: [ :nombre | nombre size > 3 ]