Tipos propios y métodos
tipo, campos con valores por defecto, métodos con @ y semántica de referencia.
tipo agrupa datos y comportamiento. Los campos pueden tener valor por defecto.
tipo Mascota
nombre cadena
energia entero = 10
fn jugar()
@energia = @energia - 2
fn inicio()
var perro = Mascota {nombre: "Toby"}
perro.jugar()
Qué es @
Dentro de un método, @ significa «este objeto», el que recibió la llamada. En perro.jugar(), @ es perro.
@energiaes el campoenergiadel objeto;@dormir()llama a otro método suyo.- Sin
@no se busca entre los campos. Un nombre suelto solo puede ser un parámetro o una variable local, así que se ve de un vistazo cuál es cuál. @solo, sin nombre, es el propio objeto como valor. Sirve para pasarlo o guardarlo. No se le puede asignar (@ = ...).
tipo Cuenta
saldo entero
fn depositar(saldo entero)
// el parámetro "saldo" y el campo "@saldo" no se confunden
@saldo = @saldo + saldo
fn mostrar()
imprimir("saldo: ${@saldo}")
fn registrar_en(banco Banco)
banco.cuentas.agregar(@) // guarda una referencia a esta cuenta
tipo Banco
cuentas [Cuenta]
Semántica de referencia
Las variables de un tipo no contienen el objeto: apuntan a él. Asignar, pasar a una función o guardar en una lista comparte el mismo objeto; nada se copia.
tipo Punto
x entero
y entero
fn mover(p Punto)
p.x = p.x + 10 // modifica el objeto original
fn inicio()
var a = Punto {x: 1, y: 2}
var b = a // b y a son el mismo objeto
b.x = 99
imprimir(a.x) // 99
mover(a)
imprimir(b.x) // 109
var lista = [a, b] // la lista guarda referencias, no copias
lista[0].y = 7
imprimir(a.y) // 7
var c = a.copiar() // objeto nuevo e independiente
c.x = 0
imprimir(a.x) // 109: a no cambió
Todo tipo trae copiar(). La copia es superficial: si el objeto tiene campos que son otros objetos, la copia comparte esos.
Embeber tipos
Para reutilizar campos y métodos, un tipo puede embeber otro escribiendo su nombre solo en una línea. Es composición, no herencia: el tipo de fuera contiene al de dentro y sus miembros se promueven.
tipo Persona
nombre cadena
fn saludar()
imprimir("Hola, soy ${@nombre}")
tipo Empleado
Persona // embebe Persona
puesto cadena
fn presentar()
@saludar() // método promovido, se llama con @
imprimir("Trabajo de ${@puesto}")
fn inicio()
var ana = Empleado {Persona: {nombre: "Ana"}, puesto: "ingeniera"}
ana.saludar() // promovido: sin escribir .Persona
ana.nombre = "Ana María" // también se puede asignar
imprimir(ana.Persona.nombre) // ruta explícita: el campo se llama Persona
// Como los objetos son referencias, se puede compartir lo embebido:
var base = Persona {nombre: "Luis"}
var jefe = Empleado {Persona: base, puesto: "gerente"}
base.nombre = "Luis Pérez"
imprimir(jefe.nombre) // Luis Pérez: jefe.Persona es el mismo objeto que base
- En el literal se usa el nombre del tipo embebido (
Persona: {...}); los campos promovidos no se pueden inicializar directamente. - Si el tipo de fuera declara un miembro con el mismo nombre, ese gana sobre el promovido.
- Los métodos promovidos cuentan para cumplir interfaces (lección 11).
Todo es privado a su archivo salvo lo marcado con pub (lección 12).
Programa completo
// Tipos propios: agrupar datos y el comportamiento que los acompaña.
tipo Mascota
nombre cadena
especie cadena
energia entero = 10 // valor predeterminado: se usa si el literal omite el campo
// Dentro de un método, @ accede a los campos del propio objeto.
fn jugar()
@energia = @energia - 2
imprimir("${@nombre} juega un rato")
fn dormir()
@energia = 10
imprimir("${@nombre} duerme")
fn estado() cadena
"${@nombre} (${@especie}) tiene energía ${@energia}"
fn inicio()
var perro = Mascota {nombre: "Toby", especie: "perro", energia: 5}
imprimir(perro.estado())
perro.jugar()
perro.jugar()
imprimir(perro.estado())
perro.dormir()
imprimir(perro.estado())
// Los objetos se comparten: otra variable apunta a la misma mascota.
var mismo = perro
mismo.nombre = "Toby Jr."
imprimir(perro.nombre)
// Al omitir "energia" en el literal, se usa su valor predeterminado.
var gato = Mascota {nombre: "Michi", especie: "gato"}
imprimir(gato.estado())
// copiar() crea un objeto nuevo con los mismos valores.
var clon = perro.copiar()
clon.nombre = "Toby clon"
imprimir(perro.nombre)
imprimir(clon.nombre)