Errors
error is a shorthand declaration for typed errors that flow as effects.
Declaration
pub error fs_err:
not_found path
denied path
invalid_path pathThis generates several pieces at once:
- A
pub enum fs_errwhose variants arenot_found path,denied path, andinvalid_path path. - A
pub act fs_errwhose operations share the variant names and returnnever. - An
impl Throw fs_errwithtype throws = '[fs_err]andour e.throwthat performs the matching effect operation. - An
impl Display fs_errwith a default text rendering (overridable with a hand-written impl). fs_err::wrapin the companion module, which closes the error effect into aresultvalue.fs_err::upin the companion module, used when other error types declarefrom fs_err.
Constructors and operations share names
Each variant name is both a data constructor and an effect operation. The surrounding context picks the right one.
my err: fs_err = fs_err::not_found path // built as a value
fs_err::not_found path // raised as an effectRaising with fail
fail is a prelude prefix operator defined as a transparent wrapper around e.throw:
pub prefix(fail) = \e -> e.throwUse it to surface a constructed error value into the effect row.
my read_text path = fs::read_text pathInferred type: roughly path -> [fs; fs_err] str. The error is visible in the effect row.
Catching by name
catch arms handle errors by naming each operation directly.
catch fs::read_text path:
fs_err::not_found _, _ -> "(missing)"
fs_err::denied _, _ -> "(denied)"
value -> valueYulang's error story is built on catching by name. There is no type-erased catch-all and no runtime dispatch over arbitrary Display instances; Yulang intentionally does not provide an anyhow-style boundary. Each error keeps its concrete type in the effect row, so the origin and the handler of every error are visible from types alone.
wrap: closing into a value
my read_text_safe path = case fs_err::wrap: fs::read_text path:
result::ok text -> text
result::err err -> err.showE::wrap catches the matching error effect produced by its thunk argument and returns result _ E. When E has from entries, wrap also catches the linked narrower errors and wraps them through the generated Cast impls.
from aggregation
pub error io_err:
fs from fs_err
parse from parse_errThis generates:
- variants
io_err::fs fs_errandio_err::parse parse_err. Cast fs_err -> io_errandCast parse_err -> io_errimpls.- an extended
io_err::wrapthat also catchesfs_errandparse_err. io_err::up, a handler that turns the narrower errors intoio_err.
my read_and_parse path =
io_err::up:
my text = fs::read_text path // [fs_err]
parse_json text // [parse_err]
// the block as a whole has effect [io_err]See also Casts for the underlying conversion machinery and Effects for the general catch and effect-row story.