lunes, 15 de agosto de 2016

Seguimos con Smalltalk, parte 2


Mensajes: Los mensajes representan la interacción entre los componentes de un sistema Smalltalk. Un mensaje es un pedido que un objeto le hace a otro objeto.

Un mensaje está compuesto por el receptor (el objeto al que se le hace el pedido), el selector (el nombre del mensaje) y, si corresponde, por los argumentos.

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

Mensajes Unary: Los mensajes Unary son mensajes sin argumentos. Son los más simples y constan de: receptor mensaje.

-1 abs.
2 class.
1000 factorial.
'aeiou' size.
Date today.
Time now.
OrderedCollection new.
#símbolo class.
String category.

Mensajes Binary: Los mensajes Binary están compuestos de la siguiente forma:

receptor unOperador argumento.

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

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

3 + 5.
3 > 7.
3 = 5.
2 @ 10.
'Un String ', 'concatenado a otro'.
'Alan Kay' -> Smalltalk.

Mensajes Keyword: Los mensajes Keyword están formados con 1 ó más palabras clave, con sus respectivos argumentos, con la forma:

receptor palabraClave1: argumento1.

O de la forma:

receptor palabraClave1: argumento1 palabraClave2: argumento2.

Y así con 3, 4 ó más palabras claves y sus argumentos.

'Un String' first: 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'

Valor de retorno: El lenguaje Smalltalk provee un mecanismo doble de comunicación.  El selector y los argumentos del mensaje permiten que el emisor le envíe información al receptor. Por otro lado 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 especificar el valor de retorno usando el caracter ^.

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


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"


Cascading messages: A veces es necesario enviarle varios mensajes al mismo receptor.  En el lenguaje Smalltalk hay una forma sintáctica de enviar más de un mensaje al mismo receptor.

La forma es terminar el envío del primer mensaje con el carácter punto y coma (;) y a continuación escribir el siguiente mensaje.

Transcript
    clear;
    show: 'algo en el Transcript'; cr;
    show: 'y algo más'; cr.

Precedencia: Los mensajes se evalúan de izquierda a derecha. Los mensajes Unary tienen precedencia sobre los Binary, y a su vez los Binary tienen precedencia sobre los mensajes Keyword.  Siempre se pueden romper las reglas de precedencia utilizando paréntesis.

'string' at: -2 negated   >>>   'string' at: (-2 negated)

'string' at: 2 + -1 negated   >>>   'string' at: (2 + (-1 negated))

Las simples reglas de precedencia, de la sintaxis Smalltalk, tienen algunas implicaciones desconcertantes para personas acostumbradas a otros lenguajes de programación.  En Smalltalk el compilador NO sabe de, por ejemplo, sumas y multiplicaciones.  Eso quiere decir que el compilador no puede determinar que, cuando operamos con números, la multiplicación tiene precedencia sobre la suma.

Analicemos esta sentencia:

3 + 2 * 4   >>>    20

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 en otros lenguajes.

Siempre podemos utilizar paréntesis para forzar la precedencia que deseamos:

3 + (2 * 4)   >>>    11

Variables: La memoria disponible para un objeto se organiza en variables.  Las variables tienen un nombre y cada una hace referencia a un único objeto en cada momento.  El nombre de las variables puede ser usados en expresiones que quieran referir a ese objeto.

métodoDeEjemplo: argumento
    "Este método muestra el uso de diferentes tipos de variables.
    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
                                                    ].

El nombre de las variables está compuesto por una secuencia de letras y dígitos, empezando con una letra. Las variables temporales y de instancia comienzan con una letra minúscula, las globales comienzan con una letra mayúscula.  Otra convención en lo que respecta al nombre de las variables es que si este está compuesto de varias palabras, cada una (excepto la inicial en algunos casos) debe comenzar por mayúscula.

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

Cuando se crear una clase, el Smalltalk crea una variable global que 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.

Un literal siempre se refiere a un único objeto pero una variable puede referirse a diferentes objetos en diferentes momentos.

Asignación: El objeto referenciado por una variable cambia cuando una asignación es evaluada.  Las asignaciones, en Smalltalk, tienen la forma:

variable := ExpresiónSmalltalk.

x := 0.
y := 1.
punto := x @ y.
clases := Smalltalk allClasses.

Pseudo-variables: Una pseudo-variable es un identificador que referencia a un objeto. La diferencia con las variables “normales” es que no se pueden asignar y siempre referencian al mismo objeto.

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."
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."