Showing posts with label inicialización. Show all posts
Showing posts with label inicialización. Show all posts

Sunday, October 11, 2009

Algo sobre el Lenguaje Ruby (II)

En esta segunda entrega, veremos algo sobre estilos de código en Ruby, y luego algunos ejemplos de programación de objetos básicos en Ruby, basándonos en algunos TPs de la materia Programación III.

Estilos de código:

Hay varias cuestiones a tener en cuenta a la hora de programar en objetos en Ruby. Como en Smalltalk, se sigue la convención de que la clases se definen con mayúscula en la primer letra, las instancias y sus variables con minúscula, así como los métodos.

Las constantes se escriben todo en mayúscula.

La diferencia principal con el estilo “smalltalkero” es que los nombres con mas de una palabra se escriben de manera diferente: Mientras que en Smalltalk una variable o métodos se escribe estoEsElNombreClasicoDeUnaVariableSmalltalk, Ruby tiene por convención que sea esto_es_un_nombre_tipico_en_ruby.

Las convenciones son importantes, dado que todos los métodos, funciones, módulos, clases y demás cosas de las librerías se escriben siguiendo estas reglas, con lo cual, no adaptarnos a ellas puede traer problemas.

Un ultimo detalle es que algunos nombres de métodos en Ruby terminan con el signo '?'. Cada vez que un método termina con el signo de interrogación significa que retorna siempre verdadero o falso. En el caso que el método termine con '!', implica que el objeto al cual le enviamos el mensaje sera modificado. Es como una advertencia de alerta, por decirlo de alguna manera.

Implementaciones y pruebas referidas al TP 2 de Programación III en Ruby

Abrimos nuestro editor de textos preferido y copiamos lo siguiente:

class Persona

# Definimos getters
def get_nombre()
return @nombre
end

def get_apellido()
return @apellido
end

def get_dni()
return @dni
end

def get_padre()
return @padre
end

def get_madre()
return @madre
end

# Definimos setters
def set_nombre(nombre)
@nombre = nombre
end

def set_apellido(apellido)
@apellido = apellido
end

def set_dni(dni)
@dni = dni
end

def set_padre(padre)
@padre = padre
end

def set_madre(madre)
@madre = madre
end

end


Observemos que los getters y los setters son similares, y solo cambia la variable a la que esta definida. Existen métodos dentro de Ruby que permiten automatizar la creacion de setters y getters. Ellos son:

attr_reader: Para creación de getters
attr_writer: Para creación de setters
attr_accessor: Para creación de getters y setters

El código anteriormente presentado se reduciría al siguiente

class Persona
attr_accessor :nombre, :apellido, :dni, :padre, :madre
end

Con esta ultima implementación abrimos un interprete interactivo (irb) y hacemos algunas pruebas(En negrita las lineas ingresadas por el usuario):

$ irb
irb(main):001:0> require 'Personas_con_accesors'

=> true
irb(main):002:0> p = Persona.new()

=> #
irb(main):005:0> p.methods

=> ["inspect", "tap", "clone", "public_methods", "__send__", "object_id", "instance_variable_defined?", "apellido", "equal?", "freeze", "extend", "apellido=", "send", "methods", "hash", "dup", "to_enum", "instance_variables", "dni", "eql?", "instance_eval", "id", "dni=", "singleton_methods", "taint", "enum_for", "frozen?", "instance_variable_get", "instance_of?", "padre", "display", "to_a", "method", "type", "padre=", "instance_exec", "protected_methods", "==", "===", "instance_variable_set", "kind_of?", "madre", "respond_to?", "to_s", "class", "madre=", "private_methods", "=~", "tainted?", "__id__", "nombre", "untaint", "nil?", "is_a?", "nombre="]
irb(main):010:0> p.public_methods(false)

=> ["padre", "madre=", "nombre=", "dni", "padre=", "apellido", "dni=", "madre", "nombre", "apellido="]
irb(main):011:0> p.nombre="Ana"

=> "Ana"
irb(main):012:0> p.apellido="Garcia"

=> "Garcia"
irb(main):013:0> p.dni=33221256

=> 33221256
irb(main):014:0> p.nombre

=> "Ana"
irb(main):015:0> p2 = Persona.new

=> #
irb(main):016:0> p2.nombre="Jose"

=> "Jose"
irb(main):017:0> p2.apellido="Taringa"

=> "Taringa"
irb(main):018:0> p.padre=p2

=> #
irb(main):019:0> p.inspect

=> "#>"
irb(main):020:0> exit

$

Hemos visto hasta aquí la implementación de métodos y clases en sus formas básicas.

Pasemos a definir ahora un método para inicializar el objeto. Sabemos que el método para inicializar un objeto es una función que asigna a las variables de instancia los valores adecuados para que el objeto funcione en el sistema sin problemas. Como todas las variables sin valor se inician con nil, sabemos que no es conveniente para operar, siempre es conveniente tener un mensaje de inicialización de los objetos.

class Persona

attr_accessor :nombre, :apellido, :dni, :padre, :madre

def initialize(nombre, apellido, dni, padre="", madre="")
@nombre = nombre
@apellido = apellido
@dni = dni
@padre = padre
@madre = madre
end
end

Un dato interesante es que el método initialize es automáticamente invocado cuando le enviamos el mensaje new a la clase. No debemos preocuparnos por la inicialización de los objetos una vez que implementamos el método de inicialización.

Si observamos la cabecera del método de inicialización

def initialize(nombre, apellido, dni, padre="", madre="")

vemos que padre y madre se asignan con cadenas vacías. Lo que estamos haciendo es asignar valores por defecto a esas dos variables. O sea, nombre, apellido y dni son obligatorios para crear un objeto de la clase Persona, pero padre y madre son opcionales.

$ irb
irb(main):001:0> require 'Personas_con_accesors_y_mensaje_de_inicializacion'

=> true
irb(main):002:0> p = Persona.new("Jose", "Taringa", 23456876)

=> #
irb(main):003:0> p.padre

=> ""
irb(main):004:0> p2 = Persona.new("Pedro", "Taringa", 14678384)

=> #
irb(main):005:0> p.padre= p2

=> #
irb(main):006:0> p.inspect()

=> "#>"
irb(main):007:0> exit

$

Por ultimo, observemos que la sentencia require se utiliza para importar módulos. Lo que va entre comillas simples es el nombre del archivo que desea importarse. Si encuentra un archivo con ese nombre en la carpeta local, lo carga (como en nuestro ejemplo), sino, busca en la librería estandar de Ruby. Si tampoco lo encuentra allí, lanza un error.

Recursos:

http://www.ruby-lang.org/es/documentation/quickstart/

http://tryruby.hobix.com/

Wednesday, September 16, 2009

Notas de la clase 2 y guía de trabajos prácticos

Iniciamos la clase con algunas preguntas sobre los temas vistos anteriormente. La pregunta clase es ¿qué es un objeto?

Basándonos en el (clásico) ejemplo de la cuenta bancaria reforzamos la idea de conocimiento y comportamiento de un objeto. El conocimiento de la cuenta son su saldo, titular y numero. Su comportamiento es devolverme su saldo, extraer y depositar.

Implementamos los métodos para una cuenta y simulamos el comportamiento de la misma haciendo que uno de los alumnos tomara el rol de la cuenta (sus variables estaban escritas en una hoja que el sostenía).  Luego vimos que podíamos tener otras cuentas como esta y llegamos al concepto de "la clase" como "molde" para la creación de instancias. Pueden leer mas sobre clases e instancias en el capítulo 1 del libro de Budd.

Recordamos que un objeto oculta su información y por tanto solo podemos acceder a su conocimiento enviándole mensajes.

Luego vimos como implementar clases y métodos en Squeak usando el browser. Interactuamos con instancias de Cuenta en el workspace. Para verificar que estuvieran funcionando bien, monitoreabamos su estado interno con inspectores. El libro Squeak by example seguro les sirve de ayuda para recordar todo sobre el browser y los menues de Squeak. También pueden dar una mirada al link que dejé en bibliografia "Squeak Smalltalk: language reference".

Nos dimos cuenta de que un objeto debe estar inicializado y hablamos del método #initialize. En squeak, el mensaje #initialize se envía automaticamente a las instancias tan pronto son creadas (ya veremos porque).

Resumimos todo lo que sabíamos sobre variables hasta ahora (de instancia, de workspace, parametros y temporales).

Finalmente terminanos de cerrar la idea de las variables como apuntadores a objeto. Esto implica que las variables de instancia de un objeto pueden apuntar a otros objetos. Esto nos permite hacer que un objeto  "conozca" a otro. El ejemplo que vimos en clase fue la Cuenta, que en su variable "titular" ya no tiene un String sino una Persona.

La guía de trabajos prácticos 2 que ya esta subida al grupo de google tiene preguntas y ejercicios para reforzar todo lo visto en clase. Haré algunas preguntas al principio de la clase que próxima.