Manejo de errores: Resultado y Opcion

Forja adopta el patrón de Resultado para operaciones que pueden fallar, y Opcion para valores que pueden estar ausentes. Ambas son variantes de tipos algebraicos definidos en el preludio.

Opcion

Úsalo cuando un valor pueda ser Algun(valor) o Ninguno. Evita el uso de nulo y fuerza el manejo explícito del caso ausente.

📦 Definición
tipo Opcion<T> = Algun(T) | Ninguno
🧪 Ejemplo
funcion primer_caracter(texto: Texto) → Opcion<Texto> {
    si (texto == "") {
        retornar Ninguno
    }
    retornar Algun(texto[0])
}

variable r = primer_caracter("forja")

coincidir (r) {
    caso Algun(c) → escribir("Primer letra: " + c)
    caso Ninguno → escribir("Vacío")
}

Resultado

Úsalo para operaciones que pueden devolver Exito(valor) o Error(mensaje).

📦 Definición
tipo Resultado<T, E> = Exito(T) | Error(E)
🧪 Ejemplo
funcion dividir(a: Entero, b: Entero) → Resultado<Entero, Texto> {
    si (b == 0) {
        retornar Error("División por cero")
    }
    retornar Exito(a / b)
}

variable r = dividir(10, 2)

coincidir (r) {
    caso Exito(valor) → escribir("Resultado: " + valor)
    caso Error(msg) → escribir("Error: " + msg)
}

Keyword resultado en contratos

La keyword resultado se usa dentro de postcondiciones (asegura) para referirse al valor de retorno de una función. Es parte del sistema de Design by Contract de Forja:

📜 Postcondición
funcion dividir(a: Entero, b: Entero) -> Entero
    requiere b != 0
    asegura resultado * b == a
{
    retornar a / b
}
💡 Las postcondiciones se evalúan después de ejecutar la función. La keyword resultado representa el valor de retorno.

Keyword anterior — valor previo en postcondiciones

La keyword anterior captura el valor de una expresión antes de ejecutar la función. Se usa dentro de asegura para referirse al estado previo:

📜 Postcondición con anterior
funcion incrementar(prestado mut x: Entero)
    asegura x == anterior(x) + 1
{
    x = x + 1
}

anterior(x) guarda el valor de x al entrar a la función. La postcondición verifica que x incrementó exactamente en 1.

Keyword siempre — Invariante de clase

La keyword siempre define invariantes de clase: condiciones que deben cumplirse siempre, antes y después de cualquier método. Si un método deja la clase en un estado inválido, el invariante se rompe:

📜 Invariante de clase
clase CuentaBancaria {
    saldo

    constructor(saldo_inicial) {
        este.saldo = saldo_inicial
    }

    funcion depositar(prestado mut cantidad: Entero)
        requiere cantidad > 0
        asegura este.saldo == anterior(este.saldo) + cantidad
    {
        este.saldo = este.saldo + cantidad
    }

    // Invariante: el saldo nunca puede ser negativo
    siempre este.saldo >= 0
}
⚠️ El invariante siempre se verifica al final de cada método de la clase. Si un método no lo cumple, se reporta un error en tiempo de ejecución.

Tabla completa de Design by Contract

KeywordDónde se usaDescripciónEjemplo
requiereFunción / MétodoPrecondición: debe cumplirse antes de ejecutarrequiere b != 0
aseguraFunción / MétodoPostcondición: se verifica después de ejecutarasegura resultado * b == a
resultadoPostcondición (asegura)Representa el valor de retorno de la funciónasegura resultado > 0
anteriorPostcondición (asegura)Captura el valor de una expresión antes de ejecutarasegura x == anterior(x) + 1
siempreClaseInvariante: condición que se cumple siempre en toda instanciasiempre este.saldo >= 0

Alias útiles del preludio

TipoDefiniciónUso común
Opcion<T>Algun(T) | NingunoValores ausentes
Resultado<T, E>Exito(T) | Error(E)Operaciones fallibles