Nyx handles I/O failures on two tiers. Tier one returns Result<T, Error> and propagates it with ?, so the caller decides what to do about the failure; tier two calls unwrap() and dies on the spot, which is the honest choice when there is no reasonable fallback. This recipe uses try_read_file and try_write_file from std/fs together with std/error.
// Errores tipados de E/S: Result<T, Error> cuando el caller reacciona, panic cuando morir es correcto import "std/fs" import "std/error" // Nivel 1 (Result): el caller de cargar_config puede reaccionar distinto // según el fallo, así que esta función NO decide por él — propaga el // Error con `?` sin necesitar saber por qué try_read_file falló. fn cargar_config(path: String) -> Result<String, Error> { let contenido: String = try_read_file(path)? return Result.Ok(contenido) } fn main() -> int { let path: String = "/tmp/nyx_example_101_config.txt" // Nivel 2 (panic): sembrar el archivo de ejemplo en /tmp. Si esto // falla, /tmp no es escribible y no hay fallback razonable — morir // acá con unwrap() es más honesto que seguir con un estado a medias. // Anotación explícita necesaria: un `let` sin tipo pierde el genérico // Result<T,E> (queda i8* opaco) y .unwrap() no dispatchea. let w: Result<int, Error> = try_write_file(path, "puerto=8080\nmodo=dev\n") w.unwrap() // Nivel 1: match exhaustivo, la config existe. match cargar_config(path) { Result.Ok(cfg) => { print(cfg) } Result.Err(e) => { print("no se pudo cargar config: " + error_to_string(e)) } } // Mismo Result, ahora el archivo no existe: el caller distingue el // tipo de fallo por e.kind sin parsear un string de mensaje. match cargar_config("/tmp/nyx_example_101_no_existe.txt") { Result.Ok(cfg) => { print(cfg) } Result.Err(e) => { print("kind: " + e.kind) } } return 0 }
puerto=8080 modo=dev kind: not_found
How it works
cargar_config is tier one: try_read_file(path)? either yields the file contents or returns early with the Error untouched. The function never has to know why the read failed — ? propagates the typed error and Result.Ok(contenido) wraps the success.
Seeding the example file under /tmp is tier two. If that write fails, the directory is not writable and there is no sensible fallback, so w.unwrap() aborts. The annotation on let w: Result<int, Error> is required: a let without a type loses the generic parameters and .unwrap() stops dispatching.
Both calls to cargar_config are matched exhaustively. The second one asks for a file that does not exist, and the Result.Err branch reads e.kind — a field of the error value, not a message to parse — which is why the last line of output is not_found.