Documentos de Académico
Documentos de Profesional
Documentos de Cultura
Tablero: contamos las filas hacia arriba, y las columnas hacia la derecha. La primera fila es la de abajo de todo, y la primera columna es la de la izquierda.
program: sección del código que declara los comandos (acciones) que queremos que la máquina realice sobre el tablero.
program {
}
Comandos primitivos o primitivas: vienen definidos por el lenguaje y nos sirven para expresar operaciones básicas:
• Mover(direccion): mueve el cabezal en el tablero en la dirección dada (Norte, Sur, Este U oeste).
• Poner(color): pone bolitas de colores (Rojo, Negro, Verde o Azul).
• Sacar(color): saca bolitas de colores
• IrAlBorde(direccion): toma una dirección, y se mueve todo lo que pueda en esa dirección, hasta llegar al borde. Es muy útil para cuando no
conocemos las condiciones de nuestro tablero.
Procedimientos: comandos que definimos nosotros, que nos sirven para expresar tareas más complejas:
procedure Poner2Rojas() {
Poner(Rojo)
Poner(Rojo)
}
Repetición simple: sirve para repetir un comando (como Mover, Poner, DibujarLineaNegra, etc) un cierto número de veces.
repeat(cantidad) {
Mover(Oeste)
}
Operadores aritméticos: + (suma), - (resta), * (multiplicación), div (se usa para dividir; por ejemplo "4 dividido 2" se escribe 4 div 2)
Alternativa condicional.
if (condicion) { acción
La condición puede ser cualquier expresión booleana (cualquier cosa que represente una "pregunta" que se pueda responder con sí o no). El sí se representa
con el valor True (Verdadero) y el no con el valor False (Falso).
La acción podrá realizarse solo cuando la condición sea verdadera.
else: significa si no. Ejecuta una serie de acciones si no se cumple la condición que pusimos en el if.
Expresiones booleanas.
Funciones: siempre retornan un valor. Pueden retornar distintos tipos: un color, una dirección, un número o un booleano.
function nombreDeLaFuncion() {
return (…..)
}
• opuesto(dirección): nos dice la dirección contraria a la dirección que nosotros le pasemos.
• siguiente(direccion): retorna la dirección siguiente a la especificada (pensándolo en el sentido de las agujas del reloj).
• previo(direccion): retorna la dirección anterior a la especificada.
• nroBolitas(color): retorna la cantidad de bolitas de un color determinado en la posición actual.
Operadores lógicos.
• not (negación): para negar una condición se agrega la palabra clave not antes de la expresión que ya teníamos. Cualquier expresión booleana (o sea,
que devuelve True o False) se puede negar.
• && (conjunción): toma dos expresiones booleanas y devuelve True solo si ambas son verdaderas
Tanto && como || pueden usarse varias veces sin la necesidad de usar paréntesis, siempre y cuando tengan expresiones booleanas a ambos lados.
Capítulo 2. Programación Imperativa - JavaScript.
Funciones: los paréntesis en el return no son necesarios y la última línea la terminamos con ;.
function doble(numero) {
return 2 * numero;
}
En JavaScript al procedimiento se lo llama función (no se escribe la palabra procedimiento). Si la función no retorna nada entonces “sería un procedimiento.” Si
la función retorna un valor entonces es una función en sí.
Funciones matemáticas.
Otra función:
tirarDado(): retorna un número al azar entre 1 y 6
Atajos.
x += y; //equivalente a x = x + y;
x *= y; //equivalente a x = x * y;
x -= y; //equivalente a x = x - y;
x++; //equivalente a x = x + 1;
xor o disyunción lógica excluyente: es verdadero si sólo una de sus proposiciones es verdadera.
No suele estar definido en los lenguajes, sin embargo, si alguna vez lo necesitás podés definirlo a mano:
Alternativa condicional
if: permite realizar una acción específica cuando se cumple una condición
if – else: permite elegir entre dos acciones diferentes (según se cumpla o no).
if – else if: permite elegir entre más de dos alternativas.
si usás adecuadamente las expresiones booleanas, ¡no es necesario utilizar esta estructura de control! En general, como regla práctica, si tenés ifs que
devuelven trues o falses, probablemente lo estás haciendo mal.
Strings (cadenas de caracteres): todos los strings están encerrados entre comillas simples o dobles (usar cualquiera).
Es una estructura de datos que permite agruparlos. Podemos tener listas de booleanos, de números, de strings, de listas.
Pueden tener elementos duplicados. En este caso, la función posicion devuelve la posición de la primera aparición del elemento en la lista.
Para averiguar qué elemento está en una cierta posición, podemos usar el operador de indexación, escribiendo después de la colección y entre corchetes [] la
posición que queremos para averiguar:
mesesDelAnio[0]
"enero"
["ese", "perro", "tiene", "la", "cola", "peluda"][1]
"perro"
¡Ojo! El número que le pases, formalmente llamado índice, debe ser menor a la longitud de la lista
For...of: es una estructura de iteración. Permite recorrer los elementos de una lista
contador: variable que se incrementa cada vez que hacemos algo dentro de un for...of o solo aquellas veces que se cumpla una condición
Registros.
Los registros, al igual que las listas, son una estructura de datos porque nos permiten organizar información.
En las listas podemos guardar muchos elementos de un mismo tipo que representen una misma cosa (por ejemplo, todos números o todos strings). No existen
límites para las listas: pueden tener muchos elementos, ¡o ninguno!
En un registro vamos a guardar información relacionada a una única cosa (por ejemplo, un monumento o una persona), pero los tipos de los campos pueden
cambiar. Por ejemplo, el nombre y la ubicación de un monumento son strings, pero su año de construcción es un número.
Una lista puede ser el campo de un registro y también podemos tener una lista de registros.
Una lista puede estar compuesta por otras listas. Un registro puede estar compuesto por otros registros dentro.
funcion:
anio(fecha): nos dice el año de una fecha
Capítulo 3. Programación con Objetos - RUBY.
Definir (crear) un objeto:
module Pepita (nombre del objeto)
end
Mensaje:
- Cuando queremos ejecutar un método de un objeto, vamos a enviarle un mensaje a ese objeto usando la siguiente sintaxis:
ObjetoReceptor.algun_mensaje
- Si a un objeto le enviamos un mensaje que no entiende, se produce un error.
- para que un objeto pueda mandarle mensajes a otro debe conocerlo. Por ejemplo, llamándolo por su nombre
- Cuando se envía un mensaje a un objeto, y este lo entiende, puede reaccionar de dos formas diferentes:
• Podría producir un efecto, es decir hacer algo. Se pone el signo de exclamación ! al final del mensaje. Por ej: el mensaje cantar! reproduce el
sonido del canto.
• O también podría devolver otro objeto. No se pone el signo de exclamación ! al final del mensaje. Por ej: el mensaje energia devuelve siempre
un número.
Todas nuestras interacciones en un ambiente de objetos ocurren enviando mensajes y las operaciones aritméticas no son la excepción a esta regla.
En el caso de 2 + 3 podemos hacer el mismo análisis:
• el objeto receptor es 2;
• el mensaje es +;
• el argumento es 3.
Argumentos
Ej: Pepita.comer_alpiste! 40
40 es un argumento del mensaje, representa en este caso que vamos a alimentar a pepita con 40 gramos de alpiste. Un mensaje podría tomar más de un
argumento, separados por coma.
un mensaje queda identificado no sólo por su nombre sino también por la cantidad de parámetros que tiene: no es lo mismo comer_alpiste! que
comer_alpiste! 67 que comer_alpiste! 5, 6, son todos mensajes distintos.
Tips
• en Ruby, a veces, los paréntesis son opcionales. Por eso, cuando no sean imprescindibles los omitiremos.
• indicar los decimales con un punto (no con una coma). La coma la usamos para separar argumentos cuando tenemos más de uno.
Método:
es la descripción de qué hacer cuando se recibe un mensaje del mismo nombre. Ej:
module Pepita
def self.cantar!
end método
end
- todos los métodos que pertenezcan al mismo objeto van dentro del mismo module.
- un método puede producir uno o varios efectos (poner uno debajo del otro). Ej:
def self.comprar_libro!
@plata -= 300
@libros += 1
end
Atributos
- se escriben anteponiendo @
- son objetos que nos permiten representar una característica de otro objeto.
- Un objeto conoce a todos sus atributos por lo que puede enviarles mensajes. Ej:
module Pepita
@energia = 100
def self.volar_en_circulos!
@energia = @energia - 10
end
end
# Suma 'valor_a_sumar' a lo contenido en @algun_atributo
@algun_atributo += valor_a_sumar es igual a @algun_atributo = @algun_atributo + valor_a_sumar
• Método getter: devuelve el valor contenido en un atributo de nombre igual al suyo. Ej:
module Pepita
@energia = 100
def self.energia
@energia
end
end
(el método energia es el getter del atributo @energia. Sin declarar este método, no tendríamos forma de saber cuánta energía tiene Pepita desde fuera de este
mismo objeto
• Método setter: modifica el valor de un atributo. Es una de las maneras posibles de cambiar el objeto al que le enviamos mensajes. Ej:
def self.firmar_contrato!(ave)
@ave = ave
end
(-17).abs
=> 17
(1710 - 1040).abs
=> 670
Delegar
(una responsabilidad)
- La delegación es la forma que tenemos en objetos de dividir en subtareas: separar un problema grande en problemas más chicos para que nos
resulte más sencillo resolverlo.
A diferencia de lenguajes sin objetos, aquí debemos pensar dos cosas:
1. cómo dividir la subtarea, lo cual nos llevará a delegar ese comportamiento en varios métodos;
2. qué objeto tendrá la responsabilidad de resolver esa tarea.
En Ruby, es una convención que los mensajes que devuelven booleanos (o sea, verdadero o falso) terminen con un ?. Ej:
def self.debil?
@energia < 100
end
Alternativa condicional - if
module Pepita
def self.hacer_lo_que_quiera!
if self.debil?
self.comer_alpiste!(10)
end
end
end
if-else
module Jardinero
def self.cuidar!(planta)
if planta.necesita_agua?
3.times { self.regar! planta }
else
self.sacar_bichos! planta
end
end
end
times: es un mensaje que entienden los números que sirve para ejecutar una porción de código varias veces. En este caso regaríamos 3 veces la planta recibida
como argumento.
Condiciones anidadas:
En otras palabras, un if dentro de un if o un else. Ej:
module Docente
def self.nota_conceptual(nota)
if nota > 8
"Sobresaliente"
else
if nota > 6
"Satisfactoria"
else
"No satisfactoria"
end
end
end
end
En Ruby, podemos simplicar la manera de escribir un if dentro un else con elsif. Ej:
def self.nota_conceptual(nota)
if nota > 8
"Sobresaliente"
elsif nota > 6
"Satisfactoria"
else
"No satisfactoria"
end
end
La rutina nos define cuál debe ser la interfaz que debe respetar un objeto para poder ser utilizado
Polimorfismo
Dos objetos son polimórficos para un tercer objeto cuando este puede enviarles los mismos mensajes, sin importar cómo respondan o qué otros mensajes
entiendan.
Si dos objetos son capaces de responder a un mismo mensaje, podemos intercambiar un objeto por otro sin notar la diferencia (el tercer objeto los puede usar
indistintamente).
Los atributos pueden ser leídos (atributo con getter), modificados (atributo con setter) o ambas cosas (atributo con getter y setter).
• Ejempo de setter:
• Ejemplo de getter:
def self.color
@color
end
#El mensaje que se enviaría para consultar cual es el color del Auto:
Auto.color #esto nos retornará el último color que se haya asignado, por ejemplo "rojo"
Encapsulamiento
Si hacemos bien las cosas, quien use nuestros objetos sólo verá lo que necesite para poder interactuar con ellos. A esta idea la conocemos
como encapsulamiento, y es esencial para la separación de responsabilidades de la que veníamos hablando.
Será tarea tuya (y de tu equipo de trabajo, claro) decidir qué atributos exponer en cada objeto.
El encapsulamiento hace que cada objeto solo exponga lo necesario para interactuar con él y se reserve para su ámbito privado lo que no sea necesario
compartir.
En el caso de los atributos, esta exposición se logra implementando un getter (método que nos permite ver su valor) o un setter (método que nos permite
modificar su valor). Y que nuestro código sea entendido fácilmente por otras personas, elegimos utilizar una convención para darle nombre a estos métodos.
Referencias
En un ambiente hay muchos objetos, pero en realidad no interactuamos con ellos directamente, sino a través de referencias, que son nombres o etiquetas que
les damos a los objetos.
Para un objeto pueden existir múltiples nombres: cuando le damos uno nuevo, no estamos creando una copia del objeto ni modificándolo realmente, sino que
estamos creando una nueva referencia que apunta al objeto. Así que ¡ojo!, si compartís un objeto con otros, y lo mutás, ¡todos los que tengan una referencia al
mismo verán los cambios!
Finalmente, en objetos, todo lo que se parezca a una variable es una referencia, y hay de muchos tipos:
• variables de un programa
• variables locales de un método
• parámetros de un método
• atributos de un objeto
• y el nombre global de un objeto bien conocido.
saludo = "hola"
saludo.upcase
=> "HOLA"
despedida = "adiós"
despedida.size()
=> 5
- Declarar una variable significa agregar una nueva referencia al objeto existente, en lugar de copiarlo.
- siempre estamos enviando el mensaje al objeto a través de una referencia.
- Dos strings con el mismo contenido no necesariamente son el mismo objeto.
- equal?: mensaje que nos dice si dos objetos son el mismo. Ej:
• lista de objetos: es un tipo de colección donde el orden importa y en la cual los elementos pueden repetirse. Es decir, el mismo objeto puede
aparecer más de una vez.
Por ejemplo, la lista de números 2, 3, 3 y 9 se escribe así: [2, 3, 3, 9]
• sets (conjuntos): otro tipo muy común de colecciones, los cuales tienen algunas diferencias con las listas:
o no admiten elementos repetidos;
o sus elementos no tienen un orden determinado.
push y delete, al ser evaluados, modifican la colección. Dicho de otra forma, producen un efecto sobre la lista en sí: agregan o quitan un elemento del
conjunto.
include? y size sólo nos retornan información sobre la colección. Son métodos sin efecto.
Sirven solo para listas:
first: retorna el primer elemento de la lista
last: retorna el último elemento de la lista
index (numero): retorna la posición de un elemento en la lista
... no podemos enviárselos a un set porque sus elementos no están ordenados.
Bloques
Los bloques son objetos que representan un mensaje o una secuencia de envíos de mensajes, sin ejecutar, lista para ser evaluada cuando corresponda. La
palabra con la que se definen los bloques en Ruby es proc.
Al bloque le enviamos el mensaje call, que le indica que evalúe la secuencia de envíos de mensajes dentro de él.
Los bloques también pueden recibir argumentos para su aplicación. Los argumentos deben estar escritos entre barras verticales | y separados por comas.
Para aplicar el bloque, se le pasan los argumentos deseados al mensaje call.
select: mensaje que recibe un bloque con un parámetro que representa un elemento de la colección y una condición booleana como código, y lo que
devuelve es una nueva colección con los elementos que la cumplen.
La colección original no modifica al aplicar select, el select no produce efecto.
Ej:
def self.consulta_con_filter
@coleccion.select{|elemento| elemento.algo?}
end
find: mensaje que devuelve únicamente un elemento de los que cumplan la condición de una colección. Y si ningún elemento de la colección cumple
la condición, devuelve nil, que es un objeto que representa la nada - o en este caso, que ninguno cumple la condición.
all?: mensaje para saber si todos los elementos de una colección cumplen un cierto criterio.
any?: mensaje para saber si algún elemento de la colección cumple cierta condición.
Mientras que select devuelve una colección y find un elemento o nil, all? y any? siempre devuelven un valor booleano: true o false.
map: mensaje que nos permite, a partir de una colección, obtener otra colección con cada uno de los resultados que retorna un envío de mensaje a
cada elemento.
En otras palabras, la nueva colección tendrá lo que devuelve el mensaje que se le envíe a cada uno de los elementos.
Al igual que el resto de los mensajes que vimos hasta ahora, map no modifica la colección original ni sus elementos, sino que devuelve
una nueva colección.
obs: ¿qué ocurriría si el mensaje dentro del bloque en el map sí tiene efecto?
En ese caso se modificaría la colección original, pero sería un mal uso del map . Lo que nos interesa al mapear es lo que devuelve el mensaje que
enviamos, no provocar un efecto sobre los objetos.
count: mensaje que nos dice cuántos elementos de una colección cumplen la condición.
sum: mensaje para calcular sumatorias.
each: mensaje que se usa cuando queremos hacer algo con cada elemento. A diferencia del map, no nos interesan los resultados de enviar el mismo
mensaje a cada objeto, sino mandarle un mensaje a cada uno con la intención de producir un efecto.
Clases
- Sirven para generalizar (agrupar) objetos que tengan el mismo comportamiento: mismos métodos y mismos atributos. Si el comportamiento no
es exactamente igual, es necesario crear una nueva clase.
- Una clase tiene métodos, atributos, pero a diferencia de en los objetos, los métodos en las clases no se preceden con la palabra self (escribir self es
optativo ).
- La clase es un objeto que nos sirve como molde para crear nuevos objetos.
- Si necesito tener muchos objetos iguales, ¡entonces quiero una clase!. Si necesito que este objeto sea único, ¡entonces puedo usar un objeto
conocido!.
Definir una clase:
class nombre
…
end
Instanciar:
bouba = Zombi.new
kiki = Zombi.new
Zombi es la clase
new: mensaje que entienden las clases, que crea una nueva instancia de esa clase
initialize: el mensaje initialize nos permite especificar cómo queremos que se inicialice la instancia de una clase.
initialize puede recibir parámetros que especifiquen con qué valores deseamos inicializar los atributos al construir nuestros objetos. Ej:
class Planta
@altura
def initialize(centimetros)
@altura = centimetros
end
end
Esto se denomina especificar un constructor: decirle a la clase cómo querés que se construyan sus instancias.
Los constructores pueden recibir más de un parámetro.
En Ruby cuando no ponemos un receptor, entiende que el mensaje se está enviando a self, es decir a sí mismo. En el caso de la clase, el self representa el objeto
instanciado a partir de la clase que recibe el mensaje.
Es decir, que es equivalente hacer:
self.atacar!(coleccion, 15)
Que hacer:
atacar!(coleccion, 15)
Nuestros objetos también pueden crear otros objetos, enviando el mensaje new a la clase que corresponda.
Por lo tanto, los casos en los que un objeto puede conocer a otro son:
• Cuando es un objeto bien conocido, como con los que veníamos trabajando hasta ahora
• Cuando el objeto se pasa por parámetro en un mensaje (Juliana.atacar bouba, 4)
• Cuando un objeto crea otro mediante el envío del mensaje new
Herencia
• Cuando dos objetos repiten lógica, creamos una clase con el comportamiento en común. En el caso que dos clases repitan lógica deberíamos crear
una nueva clase a la cual llamamos superclase. A esta nueva clase llevaremos los métodos repetidos y haremos que las clases originales hereden de
ella. Estas subclases que heredan de la superclase solo contendrán su comportamiento particular (si el método a definir es particular va en una
subclase y si es igual para todas va en la superclase)
• El símbolo < significa "hereda de". La herencia nos permite que las subclases posean los mismos métodos y atributos que la superclase
En Ruby no hay maneras de explicitar que una clase es abstracta (se usa class para superclase y clases). Al no haber una diferencia sintáctica, es decir,
cómo definimos estas clases, es responsabilidad de quien programa no instanciar aquellas clases que queremos que sean abstractas.
• las clases abstractas, a diferencia de las clases concretas, nunca las instanciamos. En otras palabras, no creamos objetos con esa clase, solo nos sirven
para proveer comportamiento a sus subclases.
• La Herencia nos permite heredar el comportamiento de una superclase pero redefinir aquellas cosas (métodos) que nuestras subclases hacen
distinto. Si se redefine el método, la clase va a evaluar ese código en lugar del de su superclase. Pero cuidado, si tenemos que redefinir todo
probablemente no necesitemos heredar en primer lugar.
• super: mensaje que, al utilizarlo en el método de una subclase, se evalúa el método con el mismo nombre de su superclase (super invoca el
método de su superclase).
Se usa para que una clase pueda hacer lo mismo que superclase y algo más
Excepciones.
raise “mensaje”: cuando lanzamos una excepción mediante raise mensaje estamos abortando la evaluación del método: a partir de ese momento todas las
sentencias que faltaba evaluar serán ignoradas. ¡Ni siquiera llega a retornar nada! (se provoca un error explícito que interrumpe el flujo del programa).
Sin embargo, las excepciones hacen más que sólo impedir que el resto del método se evalúe, sino que, cuando se lanzan, pueden abortar también la evaluación
de todos los métodos de la cadena de envío de mensajes.
Cuando trabajamos con excepciones el orden es importante: lanzar una excepción interrumpe el flujo de ejecución a partir de ese momento, pero no descarta
cambios realizados anteriormente: loque pasó, pasó.
Por eso, como regla práctica, siempre que querramos validar alguna situación, lo haremos siempre antes de realizar las operaciones con efecto.
si:
• Por un lado, el mensaje tiene que ser claro y representativo del error.
• y por otro lado, el mensaje está destinado al programador, quien lo verá cuando haya cometido algún error.
Por ese motivo, siempre procurá lanzar excepciones con mensajes de error descriptivos.