Tabla de Contenidos INTRODUCCIÓN AL LENGUAJE SMALLTALK.......................................... 2 1. BREVE RESEÑA HISTÓRICA .................................................................. 2 2. ELEMENTOS DE SMALLTALK ............................................................... 2 2.1. OBJETOS Y VARIABLES. ........................................................................... 2 2.2. MENSAJES ............................................................................................. 4 2.2.1. EXPRESIONES .............................................................................................................. 5 2.2.2. EXPRESIONES EN CASCADA ......................................................................................... 5 2.2.3. MENSAJES DENTRO DE MENSAJES ............................................................................... 5 2.3. SOBRE EL USO DE SQUEAK SMALLTALK................................................ 5 2.4. MÉTODOS .............................................................................................. 6 2.3.1. MENSAJE NEW A UNA CLASE ........................................................................................ 7 2.5. CONTROL ............................................................................................... 7 2.4.1. SELECCIÓN E ITERACIÓN .............................................................................................8 2.6. CLASES.................................................................................................. 9 2.6.1. CÓMO SE DEFINE UNA NUEVA CLASE EN SQUEAK SMALLTALK ................................ 10 Sobre la Redefinición del Método new y la Pseudo Variable super.............................. 13 2.7. HERENCIA ............................................................................................13 Introducción al Lenguaje Smalltalk 1. Breve reseña histórica Desde sus orígenes Smalltalk fue concebido para ser mucho más que un lenguaje de programación; la idea fue diseñar un ambiente de programación que integrara software y hardware, y transformara a la computadora en una herramienta fácil de usar. El sistema Smalltalk puede ser pensado como compuesto por cuatro elementos básicos: El kernel del lenguaje de programación. El paradigma de programación. El sistema de programación El modelo de interface con el usuario. Estos componentes son básicamente jerárquicos: la interface del usuario se implementa sobre el sistema de programación, el cual a su vez está construido siguiendo el paradigma de programación y usando el kernel. El kernel del lenguaje de programación es el compilador o intérprete del lenguaje, que determina la semántica y la sintaxis. El paradigma de programación es el estilo de uso del kernel, es decir, una vista del significado asignado a las entidades del mismo. El sistema de programación es el conjunto de objetos y clases del sistema necesarias para llevar a cabo la programación; este sistema brinda la estructura fundamental y resume en una colección jerárquica de clases la concepción de la programación en Smalltalk. Por último, la interface gráfica del usuario representa la utilización de las herramientas incorporadas para presentar el sistema al usuario. La combinación de todas estas piezas conforma el denominado sistema Smalltalk. El proyecto original consistió en integrar en una única plataforma de software y hardware el ambiente de programación arriba descripto. El componente de hardware tal vez no tuvo el éxito esperado por razones ajenas al proyecto mismo, la década pasada estuvo particularmente afectada por la aparición de la computadora personal cuyo impacto muchas veces no fue dimensionado con la anticipación necesaria. Pero el componente de software, es decir el sistema denominado Smalltalk/80, se convirtió en uno de los pasos fundamentales en el camino de la evolución de la programación orientada a objetos, el paradigma que más ha crecido en los últimos años. Smalltalk no sólo logró un interesante éxito en las aplicaciones industriales y administrativas sino que se convirtió en el soporte de los cursos universitarios de orientación a objetos. 2. Elementos de Smalltalk 2.1. OBJETOS Y VARIABLES. En Smalltalk, cada cosa es un objeto. No hay manera de crear dentro del lenguaje una entidad que no sea un objeto. Desde el punto de vista de la implementación, los objetos son sólo un conjunto de celdas de memoria que se asignan dinámicamente. Estas celdas mantienen el estado del objeto y a diferencia de otros lenguajes las variables no almacenan el valor que representan, sino un puntero al objeto (ver figura 1). Esta propiedad es muchas veces referida como semántica de puntero. Figura 1. Implementación de un Objeto en Smalltalk En Smalltalk existen distintas categorías de identificadores, por ejemplo, nombres y variables de clase, variables de instancia, variables globales, pseudo variables, mensajes, etc. Es importante notar que el lenguaje es sensible a mayúsculas y minúsculas. Los nombres y variables de clase deben comenzar con letras mayúsculas, mientras que las variables de instancia, pseudo variables con minúsculas. Los atributos de un objeto pueden ser de dos tipos, variables de clase y variables de instancia. Las variables de clase guardan atributos comunes a todas las instancias de una misma clase. Por lo tanto, estos atributos son accesibles a la clase y sus subclases, así como también a todos los objetos que son instancia de dichas clases. Por ejemplo, si tenemos una clase Párrafo una variable de clase puede ser sangría. Así, todos los párrafos tendrán siempre la misma sangría. En términos semánticos, si un párrafo modifica dicho atributo, estará modificando la sangría de todos los párrafos. En cambio, las variables de instancia tienen valores asociados únicamente con cada instancia u objeto creado a partir de una clase. La única manera de acceder y modificar dichos valores es a través de los métodos pertenecientes al protocolo del objeto. Por ejemplo, dada la clase Persona, una variable de instancia es el nombre de la persona. Es claro, que cada instancia de la clase Persona tendrá un nombre distinto. También es posible definir variables globales o compartidas. Estas variables son definidas en diccionarios llamados “pools”. Diferentes tipos de variables globales son definidas en diferentes tipos de pools. Todas las variables globales, al igual que las variables de clase, comienzan con letras mayúsculas. El nombre de la variable y su valor son ligados dentro de un objeto el cual es una instancia de la clase Association. Esta instancia es ubicada dentro de un pool. En particular, el “System Dictionary Smalltalk” es un pool que contiene todas las variables globales, las cuales son accesibles a todos los objetos. Note que las variables de clase son un caso particular de variables compartidas, las cuales son implícitamente almacenadas dentro de un pool definido para la clase. Retornando a la implementación, las variables en Smalltalk recuerdan a los campos de un registro en lenguajes como Pascal pero con algunas diferencias. Por ejemplo, en las variables de instancia el ámbito de referencia está delimitado por el objeto donde se encuentra la definición. Otra diferencia es que las variables son sencillamente designadores de objetos, es decir son uniformes con respecto al espacio ocupado por la referencia más allá del objeto referenciado y en este sentido no tienen un tipo asociado. Además de las variables de instancia y de clase cada objeto tiene asignada una pseudo variable denominada self. Self es un designador de objeto que representa al objeto receptor del mensaje, luego veremos que la combinación de esta variable con la herencia conforma una herramienta muy poderosa. Finalmente, Smalltalk tiene variables temporales. Las variables temporales están asociadas a un fragmento de código. Las mismas se crean cada vez que se ejecuta dicho código. El espacio ocupado por estas variables es desalocado cada vez que finaliza la ejecución del fragmento. Sintácticamente, las variables temporales son declaradas entre barras, al principio del código al que están vinculadas, y sus identificadores deben comenzar con letra minúscula. Esta categoría de variables es utilizada por los métodos. 2.2. MENSAJES La computación en Smalltalk tiene lugar como resultado de enviar mensajes a los objetos. La sintaxis indica que un mensaje se compone de una referencia al objeto receptor seguido por un indicador del mensaje en cuestión, denominado selector del mensaje, seguido de cero o más argumentos. La semántica asociada a los mensajes puede recordar las llamadas a los procedimientos, pero establece otro orden entre los componentes del lenguaje. En la programación imperativa el control ocupa el centro del diseño mientas que en la POO los mensajes y métodos están subordinados al concepto de objeto. En Smalltalk existen tres tipos de mensajes: unarios, binarios y de palabra clave. Los mensajes unarios no tienen argumentos y deben comenzar con una letra minúscula, por ejemplo: pilaUno desapilar pilaUno es el objeto receptor del mensaje, mientras que desapilar es el método o acción que se le solicita a dicho objeto. Naturalmente, el método desapilar debe formar parte del protocolo del objeto pilaUno. En cambio, los mensajes binarios, permiten pasar un argumento y su selector está formado por uno o dos caracteres no alfabéticos adyacentes. En general, se emplean para operaciones aritméticas y relacionales. Por ejemplo: x<y En este caso x es el objeto receptor del mensaje, el objeto y es el argumento y < es el selector. Como respuesta a este mensaje, x devolverá el objeto true ó el objeto false. Por otra parte, los mensajes de palabra clave permiten pasar uno o más argumentos: pilaUno apilar: 80 En este caso estamos pidiendo al objeto pilaUno que apile el objeto 80. Otro ejemplo es: vectorA at: 3 put: 19 En este caso vectorA es una instancia de la clase Array, y el mensaje at:put: esta indicando al objeto vectorA que asigne el objeto 19 al objeto que se encuentra en la posición 3 de su arreglo. Note que cada argumento tiene asociado una palabra clave, la cual debe comenzar con una letra minúscula. Finalmente, un objeto se puede enviar un mensaje a sí mismo mediante el uso de la pseudo variable self. Para ilustrar esto, asumamos que el objeto pilaUno contiene el siguiente método: apilar: unElem (self estaLlena) ifTrue: [self error: ‘pila llena’] ifFalse: [tope := tope + 1. elementos at: tope put: unElem] En este caso, self estaLlena es un mensaje que pilaUno se envía a sí misma para saber si se encuentra vacía (esto es, la búsqueda del selector error: comenzará en la clase de la cual pilaUno es intancia). 2.2.1. Expresiones Un párrafo aparte merece el tratamiento de expresiones por parte de Smalltalk. Como hemos observado antes, los números son objetos. En particular, 3 es una instancia de la clase Integer, 7.43 es una instancia de la clase Float y 4/7 es una instancia de la clase Fraction. De este modo la siguiente expresión: x := 3 + 4 asigna al objeto x el resultado de enviar el mensaje + al objeto 3 pasando como argumento el objeto 4. En definitiva, x quedará asociado el objeto 7. Es importante destacar que en Smalltalk la evaluación de las expresiones se realiza de izquierda a derecha. Además, todos los operadores tienen la misma precedencia, de este modo en la siguiente expresión 2 + 3*5 primero se efectúa la suma, luego el resultado es el objeto 25. 2.2.2. Expresiones en Cascada Existen situaciones en que necesitamos enviar varios mensajes al mismo objeto en forma consecutiva. Por ejemplo, suponga que se desea crear una pila e inmediatamente apilarle los elementos 1 y 2. Luego, se debería enviar la siguiente secuencia de mensajes: pilaUno := Pila new. pilaUno apilar: 1. pilaUno apilar: 2 Donde el mensaje new crea una instancia de la clase Pila y el mensaje apilar apila un elemento en un objeto de la clase Pila. Para estos casos, Smalltalk provee un tipo especial de expresiones conocidas como expresiones en cascada, las cuales permiten enviar múltiples mensajes a un mismo objeto. Para nuestro ejemplo, sería equivalente enviar el mensaje: pilaUno := Pila new; apilar: 1; apilar: 2 2.2.3. Mensajes dentro de mensajes Los mensajes pueden combinarse en forma poderosa. Al ser combinados, los mensajes unarios se evalúan en primer término, luego los binarios y finalmente los de palabra clave. Por ejemplo, en el siguiente mensaje: ‘casa’ size + #( 1 2 3 4) size Se evalúa primero los mensajes size, dado que son unarios y luego el mensaje +. El resultado de este mensaje es el objeto 8. 2.3. SOBRE EL USO DE SQUEAK SMALLTALK Figura 2. Ventana principal de Squeak Samlltalk Descomprima el archivo “squeak.zip” y ya puede ejecutar el archivo “squeak.exe”. Este lenguaje no necesita instalación. Una vez ejecutado el archivo squeak.exe se le presentará la ventana mostrada en la figura 2. Cierre todas las ventanas que están a la vista (en total debe cerrar 4 ventanas). De esta forma en la pantalla se verán solamente el gato y las pestañas de los bordes de la ventana principal. Para comenzar a utilizar Squeak Smalltalk haga clic con el botón izquierdo en cualquier lugar vacío de la pantalla. De esta forma accede al menú “World” que se muestra en la Figura 2. Figura 3. Menú World Las opciones a las que accederemos desde este menú son: 1) Open 2) Save Una vez elegida la opción “open” podremos optar por abrir workspace o browser, que serán las dos ventanas con las que trabajaremos. El workspace es el lugar desde el cual podremos ejecutar expresiones. El browser nos permite modificar y crear nuevas clases y métodos. Para evaluar expresiones desde el espacio de trabajo debemos escribir la expresión a evaluar, seleccionarla y clickear sobre ella con el botón derecho. Para realizar la evaluación hay tres opciones: Do It, Inspect It o Print It. Investigue la diferencia entre evaluar una expresión con cada una de estas opciones. 2.4. MÉTODOS Los objetos responden a los mensajes mediante la ejecución de métodos. Un método se compone de dos partes: un encabezado y un cuerpo. Como en los lenguajes tradicionales, el encabezado se utiliza para identificar al método cuando sea invocado y el cuerpo implementa la operación correspondiente. Por ejemplo, considere el método apilar correspondiente a la clase Pila: apilar: unElem (self estaLlena) ifTrue: [self error: ‘pila llena’] ifFalse: [tope := tope + 1. elementos at: tope put: unElem] El encabezado es apilar: unElem, donde unElem es el argumento del método. El resto constituye el cuerpo de la operación. Los métodos existen dentro de los límites demarcados por un objeto y así pueden acceder a todas las variables de instancias del mismo. Esto resume entonces dos propiedades simétricas: • • El método de un objeto sólo se interesa por el estado interno de dicho objeto. Un método no puede afectar directamente las variables de instancia de otro objeto. La principal diferencia entre los procedimientos de los lenguajes tradicionales y los métodos de Smalltalk es el momento en que se ligan la invocación (envío del mensaje) con la implementación de la operación (método). En Pascal, por ejemplo, esta ligadura se lleva a cabo en tiempo de compilación, en cambio en Smalltalk se lleva a cabo en tiempo de ejecución. 2.4.1. Mensaje new a una clase Los métodos ejemplificados anteriormente son métodos propios de las instancias de una clase. Sin embargo, de alguna manera debemos crear los objetos. Esto se logra mediante el envío de un mensaje de creación (new) a la clase del objeto. Por ejemplo, si deseamos crear el objeto pilaUno como una instancia de la clase Pila se debe realizar la siguiente asignación: pilaUno := Pila new Más adelante, en la sección 2.5 se retomará este tema. 2.5. CONTROL Las estructuras de control están implementadas mediante el mecanismo de pasaje de mensajes más una clase predefinida denominada BlockContext. Esta última brinda a Smalltalk la capacidad de encapsular una secuencia de acciones dentro de un objeto: el bloque. Un bloque es una secuencia de expresiones, separadas por puntos, y delimitada por corchetes. Asimismo, un bloque puede tener argumentos, los cuales son especificados entre el corchete izquierdo y una barra. Además cada argumento debe ir precedido por un “:”. Por ejemplo: [ :j :k | (j*k) printString ] En el bloque anterior, j y k son parámetros. Dado que un bloque es un objeto, este puede ser asignado a un identificador ó pasado como argumento de un mensaje. Para poder ejecutar un bloque sin parámetros, la clase Block provee el método value. Luego, en posible mandar el mensaje: [ I := 3. J := 8 printString ] value retornará ‘8’ Siempre, la ejecución de un bloque retorna el resultado de la última expresión evaluada dentro del mismo. Es importante notar que en respuesta al mensaje value, el bloque se ejecuta dentro del contexto en que fue definido, independientemente del contexto en que se encuentra al momento de ser ejecutado. Por ejemplo, suponga que en la clase A se define el siguiente método: metA i := 10. p := B new. ^ p metB: [i := i+1]. Además, asuma que en la clase B se define el siguiente método metB como sigue: metB: bloque i := 3+4. ^ bloque value. Luego, si a es una instancia de la clase A, y efectuamos la siguiente asignación: z := a metA resulta que z queda asignado al objeto 11. Cuando, se evaluó el mensaje ^bloque value, el objeto i del bloque hace referencia al i asignado en metA y no al empleado en metB. Por otra parte, para bloques con un argumento se emplea el mensaje value:, para el caso de dos argumentos el mensaje value:value: y así siguiendo. Por ejemplo: [ :j :k | (j*k) printString ] value: 2 value: 3 retornará ‘6’ En este caso, j y k quedan asociados a los objetos 2 y 3 respectivamente. 2.5.1. Selección En Smalltalk las estructuras de control condicionales son implementadas a través de métodos correspondientes a las subclases True y False de la clase Boolean, los cuales tienen la siguiente sintaxis: (<expresión de prueba>) ifTrue: [<secuencia-expresiones>] y (<expresión de prueba>) ifFalse: [< secuencia-expresiones>] La secuencia de expresiones colocada entre corchetes es un bloque sin argumentos. También es posible utilizarlos de manera combinada. Por ejemplo, para el método apilar tenemos: apilar: unElem (self estaLlena) ifTrue: [self error: ‘pila llena’] ifFalse: [tope := tope + 1. elementos at: tope put: unElem] El mensaje self estaLlena devuelve uno de los objetos: true o false. Si devuelve el objeto true, entonces se evalúan las expresiones del bloque que sigue a ifTrue:; si devuelve false, se evalúan las expresiones del bloque que sigue a ifFalse:. Observe que ifTrue:ifFalse: es un método definido tanto en la clase True como en la clase False; si el objeto receptor es true entonces se utiliza el método definido en la clase True, donde se envía el mensaje value al objeto block pasado como argumento en la palabra clave ifTrue:. Si en cambio, el objeto receptor del mensaje ifTrue:ifFalse: es false, luego se ejecutará el método ifTrue:ifFalse: de la clase False, donde directamente se evalúa el bloque correspondiente a la palabra clave ifFalse:. 2.5.2. Repetición Smalltalk, también define métodos en la clase Block para expresar repetición. Un bucle while por ejemplo tiene dos formas, la primera: [<secuencia-expresiones>] whileTrue: [<secuencia-expresiones>] y la segunda: [<secuencia-expresiones>] whileFalse: [<secuencia-expresiones>] En el caso de whileTrue:, el bloque receptor es repetidamente evaluado. Mientras la evaluación arroje el objeto true, el argumento del bloque es también evaluado, si no retornará el objeto nil. En el caso de whileFalse: es similar. En todos los casos, los bloques receptores deben finalizar con una expresión cuyo resultado sea instancia de la clase Boolean. Por otra parte, también se proveen métodos de la clase Integer para expresar repetición. Por caso: x timesRepeat: [< secuencia de expresiones >] x to: y do: [< secuencia de expresiones >] x to: y by: step do: [< secuencia de expresiones >] Además, la clase Collection provee los denominados ITERADORES. Estos métodos recorren de manera automática distintas estructuras de datos modeladas mediante subclases de la clase Collection, tales como la clase Array y String. Ejemplos: "cuenta las vocales de un objeto instancia de la clase String usando do:" | vowels | vowels := 0. 'Now is the time' do: [ :char | char isVowel ifTrue: [ vowels := vowels + 1 ] ]. ^vowels "dibuja varios polígonos usando do: definido en la clase Array" Window turtleWindow: 'Turtle Graphics'. #( 3 4 12 24 ) do: [ :sides | sides timesRepeat: [ Turtle go: 20; turn: 360 // sides ] ] "cuenta las vocales de un objeto instancia de la clase String usando select:" ('Now is the time' select: [ :c | c isVowel ]) size El mensaje select: itera sobre el receptor y devuelve en un nuevo String todos los elementos para los que el bloque se evalúa a true. Luego con size se obtiene la cantidad de elementos de ese String. "retorna un arreglo con los dígitos cuyo factorial es < que el dígito elevado a la 4ta potencia" #( 1 2 3 4 5 6 7 8 9 ) reject: [ :i | i factorial >= ( i * i * i * i ) ] "retorna un arreglo con los cuadrados de cada elemento del arreglo receptor" #(1 13 7 10) collect: [ :i | i * i ] Implementación de algunos de los métodos presentados anteriormente: Clase: BlockContext whileTrue: aBlock " Evaluate the argument, aBlock, as long as the value of the receiver is true." self value ifTrue: [ aBlock value. ^self whileTrue: aBlock ] Clase: Number timesRepeat: aBlock "Evaluate the argument, aBlock, the number of times represented by the receiver." | count | count := 1. [count <= self] whileTrue: [aBlock value. count _ count + 1] to: stop do: aBlock " Evaluate aBlock for each element of the interval (self to: stop by: 1)." | nextValue | nextValue := self. [nextValue <= stop] whileTrue: [aBlock value: nextValue. nextValue _ nextValue + 1] Clase: Collection do: aBlock 1 to: self size do: [:index | aBlock value: (self at: index)] La característica más importante de estas estructuras de control es la combinación de una sintaxis muy sencilla con un mecanismo básico de pasaje de mensajes que conforman una herramienta de programación muy poderosa y elegante que recuerda a la programación declarativa. En realidad, los rasgos de la programación imperativa se ocultan en las profundidades de la jerarquía de clases predefinidas por el sistema. 2.6. CLASES Una clase brinda la estructura general para objetos con características similares. El punto más interesante es que en este lenguaje las clases son objetos a los cuales se les pueden enviar mensajes como a cualquier otro objeto. Todo en Smalltalk es un objeto. Esta uniformidad extrema se traduce en que, por ejemplo, el debugger incorporado al ambiente de Smalltalk-80 también está escrito en Smalltalk y puede ser extendido o adaptado por el programador. Squeak Smalltalk tiene una gran variedad de clases predefinidas. A estas clases el programador puede agregar otras, las cuales deberán insertarse dentro de la estructura jerárquica definida por el lenguaje. 2.6.1. Cómo se define una nueva clase en Squeak Smalltalk Las descripciones de clases pueden ser ingresadas a través del Browser provisto por el lenguaje. Para ello, se debe seleccionar la opción Browser dentro del menú World. A continuación se visualizará la ventana que se muestra en la figura 4. Figura 4. Browser de clases En el resto de esta sección crearemos la clase pila. En primer lugar vamos a definir una nueva categoría en la que incorporaremos todas las clases que definimos. Para esto, debemos clickear en un cuadrado que se encuentra en la esquina superior derecha de la sección de categorías de clases (marcado con un rectángulo amarillo en la figura 4). Allí aparecerá un nuevo menú del que tenemos que seleccionar la opción “add item”. Escriba en la ventana el nombre que le dará a la nueva categoría (su nombre). Recuerde que no estamos creando todavía una clase. Solo estamos definiendo la categoría en la que quedará definida por una cuestión de organización. Al clickear en el nombre de la nueva categoría verá que la misma está vacía. Ahora sí procederemos a crear una nueva clase. Para esto debemos decidir quién será la clase padre. Crearemos la clase Pila como subclase de la clase Object. Al seleccionar la categoría recién creada podemos ver en la sección de cuerpo de los métodos una porción de código con la siguiente forma: Object subclass: #NameOfSubclass instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'NuevaCategoría' Para crear la clase debemos reemplazar NameOfSublclass por Pila. En ese punto se definen las variables de instancia de la nueva clase. Para nuestro ejemplo son: elemento, tope y cantMax. El texto queda de la siguiente manera: Object subclass: #Pila instanceVariableNames: 'elementos tope cantMax' classVariableNames: '' poolDictionaries: '' category: 'NuevaCategoría' Posteriormente se guarda esta definición seleccionando la opción Accept del menú contextual que aparece al clickear con el botón derecho en la sección en la que acaba de modificar ese texto. Para crear un nuevo método, debe seleccionar la categoría all de la sección de categorías de métodos. De esa forma verá un esqueleto de método que deberá completar como corresponda. Para nuestro ejemplo, crearemos el método Inicializar reemplazando el texto: message selector and argument names "comment stating purpose of message" | temporary variable names | statements por el texto: inicializar "metodo de inicializacion de una instancia de la clase pila" Tope:=0. cantMax:=10. Elemento:= Array new: 10. Para guardar esta nueva definición clickee nuevamente con el botón derecho y seleccione accept. Asegúrese de haber creado este método como método de instancia. Para esto debe estar clickeada la opción Instance debajo de la sección de clases. Los restantes métodos de la clase Pila son: Métodos de Clase new ^(super new) inicializar Métodos de Instancia estaVacia ^(tope = 0) estaLlena ^(tope = cantMax) apilar: unElem self estaLlena ifTrue: [self error: ‘pila llena’] ifFalse: [tope := tope + 1. elementos at:tope put:unElem] desapilar | temp | (self estaVacia) ifTrue: [self error: ‘pila vacia’] ifFalse:[temp := elementos at: tope. tope := tope - 1. temp] error: string string printString Al terminar de crear la clase o en cualquier paso intermedio recuerde grabar la imagen de Squeak para que cuando vuelva a ejecutar el programa se mantengan los cambios que realizó en el ambiente. Para esto debe acceder al menú World y elegir la opción Save. Cuando termine de trabajar con Squeak Smalltalk elija la opción Save and Quit del menú World. SOBRE LA REDEFINICIÓN DEL MÉTODO NEW Y LA PSEUDO VARIABLE SUPER En la clase Pila mostrada arriba el método de clase new fue redefinido con el fin de que toda nueva instancia de la clase esté inicializada al momento de su creación. Para ello fue necesario emplear la variable especial super. La variable self permite que un objeto pueda referenciarse a sí mismo. Sin embargo, super hace referencia al alcance de la superclase correspondiente. Luego, super permite saltear un nivel en la cadena de herencia. De este modo, cuando en el cuerpo del método se incluye la sentencia super new, este último new refiere al definido en la clase Object. De otra forma, la redefinición de new sería recursiva y su cómputo nunca finalizaría. Esta característica es muy útil cuando se desea inicializar los objetos recién creados. 2.7. HERENCIA Smalltalk implementa la herencia en el sentido introducido anteriormente. Una subclase hereda el comportamiento de la superclase. Cuando un método es invocado se inicia una búsqueda a lo largo de la cadena de clases vinculadas por esta relación, hasta finalizar en la clase Object que es la raíz de la estructura de clases predefinidas. La herencia simple establece una jerarquía en forma de árbol. Esto significa que cada clase tiene a lo sumo una superclase, aunque puede tener varias subclases. En la raíz de la jerarquía se encuentra la clase Object. Todas las clases, excepto Object, tienen exactamente una superclase. También decimos que Object constituye la metaclase de Smalltalk. Es decir la clase de la que derivan todas las clases. Una subclase hereda variables y métodos de su superclase. De este modo, las variables y métodos de instancia de la superclase se convierten automáticamente en variables y métodos de instancia de la subclase. Además de las variables heredadas, una subclase puede declarar nuevas variables de instancia. Los métodos de una subclase invalidan a los métodos heredados con igual nombre. Hemos dicho antes que un método es la implementación de una operación. Suponga que para alguna operación con nombre op, tanto la superclase como la subclase implementan métodos. En este caso, decimos que la subclase redefine el método de su superclase. Luego, los objetos que sean instancia de la subclase utilizan la implementación proporcionada por la subclase. Una excepción a esto lo constituye el uso de la variable super. En resumen, una clase tiene una superclase ‘inmediata’ y posiblemente una o más subclases, con la clase Object en la cima de la jerarquía. Las clases situadas más arriba en la jerarquía representan características más generales, mientras que clases más abajo en la jerarquía representan características más específicas (relación is-a). Un objeto hereda todas las variables de instancia definidas en sus superclases más las contenidas en su propia clase. Los métodos también se heredan. Cuando se envía un mensaje a un objeto, Smalltalk busca el método correspondiente en la clase del objeto. Si lo encuentra, lo ejecuta. En caso contrario, repite el procedimiento en la superclase del objeto. Este proceso continua hasta llegar a la clase Object. Si no se encuentra el método se produce un error.