Exit — Terminal Outcomes

Every effect execution ends with an Exit. It's the final word on what happened.

The Exit Type

#![allow(unused)]
fn main() {
use id_effect::Exit;

enum Exit<E, A> {
    Success(A),         // Effect completed, produced A
    Failure(Cause<E>),  // Effect failed with Cause<E>
}
}

Exit combines the success type and the full failure taxonomy. It's what you get when you use run_to_exit instead of run_blocking:

#![allow(unused)]
fn main() {
use id_effect::run_to_exit;

// run_blocking returns Result<A, E> — loses Cause::Die and Cause::Interrupt info
let user: Result<User, DbError> = run_blocking(get_user(1))?;

// run_to_exit returns Exit<E, A> — full picture
let exit: Exit<DbError, User> = run_to_exit(get_user(1));

match exit {
    Exit::Success(user)                    => println!("Got user: {}", user.name),
    Exit::Failure(Cause::Fail(DbError::NotFound)) => println!("User not found"),
    Exit::Failure(Cause::Die(panic_val))   => eprintln!("Defect: {:?}", panic_val),
    Exit::Failure(Cause::Interrupt)        => println!("Cancelled"),
}
}

Converting Exit to Result

Most application code wants Result. The conversion is straightforward:

#![allow(unused)]
fn main() {
let result: Result<User, AppError> = exit.into_result(|cause| match cause {
    Cause::Fail(e) => AppError::Expected(e),
    Cause::Die(_)  => AppError::Defect,
    Cause::Interrupt => AppError::Cancelled,
});
}

Or use the convenience method that maps Cause::Fail(e)Err(e) and treats other causes as panics:

#![allow(unused)]
fn main() {
let result: Result<User, DbError> = exit.into_result_or_panic();
}

Exit in Fiber Joins

When you join a fiber (Chapter 9), you get an Exit back:

#![allow(unused)]
fn main() {
let fiber = my_effect.fork();
let exit: Exit<E, A> = fiber.join().await;
}

This lets you inspect whether the fiber succeeded, failed with a typed error, panicked, or was cancelled — and respond appropriately in the parent fiber.

Practical Rule

Use run_blocking (which returns Result<A, E>) for 90% of cases. Use run_to_exit when you need to distinguish panics from typed failures — typically at top-level handlers, supervisors, or when integrating with external error reporting.